Home > database >  Transfrom array (multiple depth object keys) into one object
Transfrom array (multiple depth object keys) into one object

Time:10-29

Task: Transform array of keys into one object and assign each key with an empty string e.g.("").

Problem: Keys are also representing different levels of depth in the result object (e.g. defaultToolConf.graph.graphApiConf.url represents 4 levels of depth in object). Each level of depth is separated by a dot(.) in a key string.

Input (array):

[
'ADMIN_URL_REGEXP', 
'BASE_PATH', 
'appName', 
'defaultToolConf',
'defaultToolConf.graph', 
'defaultToolConf.graph.graphApiConf', 
'defaultToolConf.graph.graphApiConf.markerCampaignsUrl',
'defaultToolConf.graph.graphApiConf.markerUrl', 
'defaultToolConf.graph.graphApiConf.ndviUrl', 
'defaultToolConf.graph.graphLineColors', 
'defaultToolConf.query', 
'defaultToolConf.query.canExportKml', 
'defaultToolConf.query.isExportEnabled', 
'defaultToolConf.query.isResizable', 
'defaultToolConf.test', 
'defaultToolConf.toolsPermissionsPath', 
'token', 
'token.format', 
'token.key', 
'token.paths'
]

Output (result object):

{
    "ADMIN_URL_REGEXP": "",
    "BASE_PATH": "",
    "appName": "",
    "defaultToolConf": {
        "graph": {
            "graphApiConf": {
                "markerCampaignsUrl": "",
                "markerUrl": "",
                "ndviUrl": ""
            },
            "graphLineColors": ""
        },
        "query": {
            "canExportKml": "",
            "isExportEnabled": "",
            "isResizable": ""
        },
        "test": "",
        "toolsPermissionsPath": ""
    },
    "tokenInterceptor": {
        "format": "",
        "key": "",
        "paths": ""
    }
}

What I have done so far: https://jsfiddle.net/rt279mfz/

I managed to create a result object with multiple depth objects.

Problems: I had to assign key values as empty object {}. That means I would have to loop through all object keys (in multiple depths) and reassign values as an empty string instead of an empty object. I don't know if that is possible.

I have repeating keys in the result object.

CodePudding user response:

You can "walk" through the object, creating sub-levels as you go. Here's an example:

const array = [
    'ADMIN_URL_REGEXP', 
    'BASE_PATH', 
    'appName', 
    'defaultToolConf',
    'defaultToolConf.graph', 
    'defaultToolConf.graph.graphApiConf', 
    'defaultToolConf.graph.graphApiConf.markerCampaignsUrl',
    'defaultToolConf.graph.graphApiConf.markerUrl', 
    'defaultToolConf.graph.graphApiConf.ndviUrl', 
    'defaultToolConf.graph.graphLineColors', 
    'defaultToolConf.query', 
    'defaultToolConf.query.canExportKml', 
    'defaultToolConf.query.isExportEnabled', 
    'defaultToolConf.query.isResizable', 
    'defaultToolConf.test', 
    'defaultToolConf.toolsPermissionsPath', 
    'token', 
    'token.format', 
    'token.key', 
    'token.paths'];
    
const arrayToObject = (arr) => {
  return arr.reduce((acc, el) => {
    let currentNode = acc;
    const pathParts = el.split(".");
    for (let i = 0; i < pathParts.length - 1; i  ) { // skip the final element (- 1)
      let pp = pathParts[i];
      if (!currentNode[pp])
        currentNode[pp] = {}; // create the nested object if needed
      currentNode = currentNode[pp]; // move to the next level of the object
    }
    // currentNode is now the parent object of the last property from the array that we need to add, from here we just assign it to ""
    currentNode[pathParts[pathParts.length - 1]] = "";
    return acc;
  }, {});
}

let newObject = arrayToObject(array);
console.log(newObject);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Iterative:

// Reduce 
const result = array.reduce((acc, item) => {

  // Split string to array
  const split = item.split('.');

  let currentStep = acc;

  split.forEach((item, index) => {
    // Set current object property (if already exists do nothing, if not then create an empty object, if its last index assign empty string)
    currentStep = currentStep[item]
                = (currentStep[item] || (index === split.length - 1 ? '' : {}))

  });

  return acc;

}, {})

Recursion:

const result = array.reduce((acc, item) => {

  const createDeepNestedObj = (obj, array, index = 0, current = array[index]) => {

    obj[current] = obj[current] || (index < array.length - 1 ? {} : '');

    if (index < array.length) createDeepNestedObj(obj[current], array,   index);
  }

  createDeepNestedObj(acc, item.split('.'));

  return acc;

}, {})
  • Related