2

I have an array with objects, that can have children, the children have the same structure as the parent, it's just object nesting basically.

I'm wondering how I can flatten the structure of my objects so I have the id's of all the objects, including the nested one's.

For example, This structure

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]

Should be flattened to this

const data = [2,1,3]

I've tried

Using Array.reduce() and the object spread syntax, but I can't wrap my head around the logic required to do this.

Miguel Stevens
  • 8,631
  • 18
  • 66
  • 125

9 Answers9

4

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]

const getIds = (data) => data.map(d => [d.id, ...getIds(d.children)]).flat()

console.log(getIds(data))
wang
  • 1,660
  • 9
  • 20
3

This is a job for recursion. Loop over the array and for each element in it, push the id into a new array and repeat for the children.

const data = [{
    id: 2,
    children: [{
      id: 1,
      children: []
    }]
  },
  {
    id: 3,
    children: [],
  }
];

console.log(flatten(data));

function flatten(data) {
  const result = [];
  recursive(data);
  return result;

  function recursive(data) {
    data.forEach(member => {
      result.push(member.id);
      recursive(member.children);
    });
  }
}
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
1

You can use JSON.stringify, and for each key of id, push to an array:

const data = [
  {
    id: 2,
    children: [
      {
        id: 1,
        children: []
      }
    ]
  },
  {
    id: 3,
    children: [],
  }
]
const ids = [];
JSON.stringify(data, (key, val) => {
  if (key === 'id') {
    ids.push(val);
  }
  return val;
});
console.log(ids);
Snow
  • 3,820
  • 3
  • 13
  • 39
1

You can do some recursive approach.

function flatArr(arr, res) {
  // iterate over the array
  arr.forEach(o => {
    // check id is present then push it into the result array
    if ('id' in o) res.push(o.id)
    // check children is present and non-empty
    // then ecursively call the function
    if (o.children && o.children.length) flatArr(o.children, res);
  })
  // return the result array(optional)
  return res;
}

console.log(flatArr(data, []));

const data = [{
    id: 2,
    children: [{
      id: 1,
      children: []
    }]
  },
  {
    id: 3,
    children: [],
  }
];

function flatArr(arr, res) {
  // iterate over the array
  arr.forEach(o => {
    // check id is present then push it into the result array
    if ('id' in o) res.push(o.id)
    // check children is present and non-empty
    // then ecursively call the function
    if (o.children && o.children.length) flatArr(o.children, res);
  })
  // return the result array(optional since it's the same array reference you are passing initially)
  return res;
}

console.log(flatArr(data, []));
Pranav C Balan
  • 113,687
  • 23
  • 165
  • 188
1

You could reduce the array of objects by using the actual id and get their children objects.

const
    getId = array => array.reduce(
        (r, { id, children }) => [...r, id, ...getId(children)],
        []
    ),
    data = [{ id: 2, children: [{ id: 1, children: [] }] }, { id: 3, children: [] }],
    ids = getId(data);
    
console.log(ids);
mplungjan
  • 169,008
  • 28
  • 173
  • 236
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

You can use recursion.Note that is below code reference of arr is passed so we can directly push() ids to it and no need to get return value

const data = [{ id: 2, children: [{ id: 1, children: [] }] }, { id: 3, children: [], } ]

function getIds(data,arr){
  //iterate over array of chilren
  for(let child of data){
    //add id of each child to arr
    arr.push(child.id);
    //check if child have children add its 'ids' to same array
    if(child.children) getIds(child.children,arr);
  }
  //return array in end
  return arr;
}
console.log(getIds(data,[]))
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
1

I do not like recursions :)

Do note the other Stringify answer - ILST
https://stackoverflow.com/a/55179326/295783

const data=[{id:2,children:[{id:1,children:[]}]},{id:3,children:[],}];

console.log(
  JSON.stringify(data)
    .match(/(?:"id":)(\d+)/g)
    .map(v => +v.replace(/"id":/g, ""))
)

I however wish someone could find me a way to ignore the non-capturing group in one go

mplungjan
  • 169,008
  • 28
  • 173
  • 236
0

You can use a recursive approach and iterate for each children and push all the id in an array.

const data = [{ id: 2, children: [{ id: 1, children: [] }] }, { id: 3, children: [], } ],
      getId = (data) => data.reduce((r,{id, children}) => r.concat(id, getId(children)),[]);
console.log(getId(data));
Hassan Imam
  • 21,956
  • 5
  • 41
  • 51
0

Another version. Not the prettiest but gets the job done:

const data = [
    {
        id: 2,
        children: [
            {
                id: 1,
                children: []
            }
        ]
    },
    {
        id: 3,
        children: [],
    }
];
    
let mappedArray = data.map(num => [].concat(num.children.map(child => child.id)).concat(num.id));
    mappedArray = [].concat.apply([], mappedArray);

console.log(mappedArray);
Lewis
  • 3,479
  • 25
  • 40