Skip to content
Advertisement

How to add dynamic keys with nested level from the array in javascript

Hi I want to create new object on the basis of path array. It will be dynamic. I tried with reduce but it is not giving correct result.

const obj = {
  "e": [{
      "name": "moviename",
      "path": ["a"]

    },
    {
      "name": "hero",
      "path": ["a", "b"]
    },
    {
        "name": "desc",
      "path": ["c"]
    },
    {
        "name": "udf",
      "path": []
    }
  ]
}
    

// this is what i want this object to be created programatically. after parsing above obj.

const output = {
  "a": {
    "moviename": "",
    "b": {
      "hero": ""
    }
  },
  "c" : {
    "desc": ""
  },
  "udf": ""
}

const payload = {};
obj.e.forEach((item) => {
  if (item.path.length === 0) {
    payload = {
      ...payload,
      [item.name]: ''
    };
  } else {
    item.path.reduce((o, s, index) => {
      if ((index + 1) === item.path.length) {
        return o[s] = {
          [item.name]: ''
        };
      }
      return o[s] = {};
    }, payload);
  }
});

console.log(payload);

Advertisement

Answer

You can use simple for loops — reduce would also work (see further down), but I think the overhead of a callback is not worth it:

function convert(arr) {
    const output = {};
    for (const {name, path} of arr) {
        let node = output;
        for (let prop of path) {
            node = (node[prop] ??= {});
        }
        node[name] = "";
    }
    return output;
}

const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};

console.log(convert(obj.e));

With reduce:

Using reduce it would translate to this:

function convert(arr) {
    return arr.reduce((output, {name, path}) => {
        let node = output;
        for (let prop of path) {
            node = (node[prop] ??= {});
        }
        node[name] = "";
        return output;
    }, {});
}

const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};

console.log(convert(obj.e));

With double reduce:

If the inner loop is also done through reduce, then:

function convert(arr) {
    return arr.reduce((output, {name, path}) => {
        path.reduce((node, prop) => node[prop] ??= {}, output)[name] = "";
        return output;
    }, {});
}


const obj = {"e": [{"name": "moviename","path": ["a"]},{"name": "hero","path": ["a", "b"]},{"name": "desc","path": ["c"]},{"name": "udf","path": []}]};

console.log(convert(obj.e));

The logical nullish assignment operator

If your environment has no support for ??= then use one of the following alternatives:

  • node[prop] ||= {}
  • (node[prop] = node[prop] ?? {})
  • (node[prop] = node[prop] || {})

Some comments on your code

As this function builds the object from scratch, it is not really necessary to treat intermediate versions of the object as immutable — as your code attempts to do at least in the case of path.length == 0: just keep extending the object through mutation.

return o[s] = {}; is destructive: if the property was already created from a previously processed path, then this will overwrite whatever was already assigned to o[s].

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement