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.

0

9 Answers 9

5

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))

Sign up to request clarification or add additional context in comments.

2 Comments

This is elegant
I've accepted this answer, like the one-line! Thanks
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);
    });
  }
}

Comments

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);

2 Comments

Ohhh - Cool. I had no idea stringify took parameters. I also used stringify and then a regex
Strangely enough this does not recurse: JSON.stringify(data,["id"])
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, []));

Comments

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,[]))

Comments

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

2 Comments

Convert each value to Number. Really odd solution +1
@MaheerAli Done ;)
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);

Comments

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));

Comments

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.