0

I'm attempting to write a function that will loop through a deeply nested object, and create a shallow object by concatenating parent/child keys.

For example, if we have the object:

let original = {
  a: {
    b: "",
    c: { 
      d: "",
      e: ""
    },
    f: "",
  },
  g: ""
}

Then I would like the outcome to be this:

let result = {
  "a[b]": "",
  "a[c][d]": "",
  "a[c][e]": "",
  "a[f]": "",
  "g": ""
}

I've got as far as the code snippet below, but it's not quite correct.

let original = {
  a: {
    b: "",
    c: {
      d: "",
      e: ""
    },
    f: "",
  },
  g: ""
}

function flattenData(obj) {
  let result = {};

  for (let i in obj) {
    if ((typeof obj[i]) === 'object') {
      let temp = this.flattenData(obj[i])
      for (let j in temp) {
        result[`[${i}][${j}]`] = temp[j];
      }
    } else {
      result[i] = obj[i];
    }
  }
  return result;
}

console.log(flattenData(original));
  • Hi you can also use SO code snippet https://meta.stackoverflow.com/questions/356678/stack-overflow-run-code-snippet – ikhvjs Aug 20 '21 at 10:49
  • 2
    Also, your result is correct for me. and your expected result is not correct. `"a[g]": ""` is not correct in the expected result because `g` is not inside `a`. – ikhvjs Aug 20 '21 at 10:52
  • Take a look at the approaches from https://stackoverflow.com/q/19098797/1048572 – Bergi Aug 20 '21 at 11:06
  • Thank you that's right, `g` should not be inside `a`. –  Aug 20 '21 at 11:58

2 Answers2

1

We can use a recursive approach as you have done, we'll keep a path array and a result object to keep our state as we recurse through the object, this should give us the result we desire.

Note: I believe the last property in the result should be "g": "" rather than "a[g]": "" since g is not a property of a in the original object.

let original = {
  a: {
    b: "",
    c: { 
      d: "",
      e: ""
    },
    f: "",
  },
  g: ""
}

function flattenData(obj, path = [], result = {}) {
    for(let k in obj) {
        if (typeof(obj[k]) === 'object') {
            flattenData(obj[k], [...path, k], result)
        } else {
            const resultKey = [...path, k].reduce((acc,s,i) => acc + (i ? `[${s}]`: s) );
            result[resultKey] = obj[k]
        }
    }
    return result;
}

console.log('Result =', flattenData(original))
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
0

You can flatten the nested object using array#reduce and Object.entries() in a recursive manner.

const original = { a: { b: "", c: { d: "", e: "" }, f: "", }, g: "" },
      objectCondition = val => typeof val === 'object' && val !== null,
      flatten = (obj, prefix = "") => {
      return Object.entries(obj).reduce((r, [key, val]) => {
          const prop = prefix ? `${prefix}[${key}]`: key;
          const o = objectCondition(val) ? flatten(val, prop) : {[prop]: val};
          return {...r, ...o};
        }, {});
      }
console.log(flatten(original));
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51