Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recursively transform an array of nested objects into array of flat objects?

I have the following array of deeply nested objects:

const data = [
    {
      name: "foo",
      children:[
        {
          count: 1,
          name: "A"
        },
        { 
          count: 2,
          name: "B"
        }
      ]
    },
    {
      name: "bar",
      children: [
        {
          count: 3,
          name: "C",
          children: [
            {
              count: 4,
              name: "D"
            }
          ]
        }
      ]
    }
  ]

The way I'd like to transform this would be such as:

const expectedStructure = [
    {
      count: 1,
      name: "A",
      label: "foo = A"
    },
    {
      count: 2,
      name: "B",
      label: "foo = B"
    },
    {
      count: 3,
      name: "C",
      label: "bar = C"
    },
    {
      count: 4,
      name: "D",
      label: "bar = D"
    }
  ]

I created recursive function that transforms nested array into array of flat objects.

Here's my code:

function getChildren(array, result=[]) {
    array.forEach(({children, ...rest}) => {
        result.push(rest);
        if(children) {
            getChildren(children, result);
        }
    });
    return result;
}

And here's output I get:

[ { name: 'foo' },
  { count: 1, name: 'A' },
  { count: 2, name: 'B' },
  { name: 'bar' },
  { count: 3, name: 'C' },
  { count: 4, name: 'D' } ]

The problem is that I need to add label field to every object in my output array, and I can't find a solution without iterating multiple times through the final array to make desired transformation. How to properly insert label field without hugely augmenting complexity of the function?

like image 568
Martin Avatar asked Nov 24 '25 02:11

Martin


1 Answers

Check each iteration whether the current item is a "parent" item, and reassign label if it is.

const data = [{name:"foo",children:[{count:1,name:"A"},{count:2,name:"B"}]},{name:"bar",children:[{count:3,name:"C",children:[{count:4,name:"D"}]}]}];

function getChildren(array, result = [], label = "") {
  array.forEach(({ children, name, count }) => {
    if (!label || name[1]) {
      label = `${name} = `;
    }
    if (count) {
      result.push({ count, name, label: label + name });
    }
    if (children) {
      getChildren(children, result, label);
    }
  });
  return result;
}

const res = getChildren(data);

console.log(res);
like image 92
Jack Bashford Avatar answered Nov 25 '25 15:11

Jack Bashford