Flatten nested objects, keeping the properties of parents

Viewed 211

I have a data structure that has this shape:

[
  {
    a: "x",
    val: [
      { b: "y1", val: [1, 2, 3] },
      { b: "y2", val: [4, 5, 6] },
    ],
  },
];

An example with 3 levels:

[
  {
    a: "x",
    val: [
      { b: "y1", val: [
        {c: "z1", val: [1, 2]}
      ] },
      { b: "y2", val: [
        { c: "z2", val: [3, 4] },
        { c: "z3", val: [5, 6, 7] },
        { c: "z4", val: [8] }
      ]  },
    ],
  },
];

Each object always has the same level of nesting, and I know the max depth of nesting in advance. We also know the names of the keys in advance: we know that the key at level 1 will be named a, the one at level 2 will be named b, and so on.

I'm looking to create a function that transforms the first example into:

[
    {
      a: "x",
      b: "y1",
      val: [1, 2, 3],
    },
    {
      a: "x",
      b: "y2",
      val: [4, 5, 6],
    },
];

that is, a flat array with values and keys inherited from parents.

I've got a solution which works for the first example:

const res = [
  {
    a: "x",
    val: [
      { b: "y1", val: [1, 2, 3] },
      { b: "y2", val: [4, 5, 6] },
    ],
  },
].flatMap((x) => x.val.flatMap((d) => ({ a: x.a, ...d })));
console.log(res);

but I'm struggling to turn it into a recursive function.

Thank you in advance for your help!

1 Answers

You could have a look to the arrays and if no objects inside return an object, otherwise map val property by storing other properties.

const
    isObject = o => o && typeof o === 'object',
    flat = array => {
        if (!array.every(isObject)) return { val: array };
        return array.flatMap(({ val, ...o }) => {
            const temp = flat(val);
            return Array.isArray(temp)
                ? temp.map(t => ({ ...o, ...t }))
                : { ...o, ...temp };
        });
    },
    data0 = [{ a: "x", val: [{ b: "y1", val: [1, 2, 3] }, { b: "y2", val: [4, 5, 6] }] }],
    data1 = [{ a: "x", val: [{ b: "y1", val: [{ c: "z1", val: [1, 2] }] }, { b: "y2", val: [{ c: "z2", val: [3, 4] }, { c: "z3", val: [5, 6, 7] }, { c: "z4", val: [8] }] }] }];

console.log(flat(data0));
console.log(flat(data1))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related