Ryan King
Ryan King

Reputation: 3696

Get deepest level children from nested objects in javascript

I have 2 types of a objects, a group, and an item. A group can have children which is either an array of groups or an array of items.

I've ended up with a series of nested groups (which can be infinite levels deep) and I need to retrieve all the items, no matter how many levels deep, with only a group to work with.

Is there a way to retrieve all the items from the top-level group in the following data structure?

{
  type: 'group',
  children: [
    {
      type: 'group',
      children: [
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}, {type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}, {type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}, {type:'item'}]
        },
      ]
    },
    {
      type: 'group',
      children: [
        {
          type: 'group',
          children: [{type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}]
        },
      ]
    },
    {
      type: 'group',
      children: [
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}]
        },
        {
          type: 'group',
          children: [{type:'item'}, {type:'item'}]
        },
      ]
    },
  ]
}

Upvotes: 3

Views: 4837

Answers (2)

Nina Scholz
Nina Scholz

Reputation: 386670

You could use an iterative with Array#reduce and recursive with calling iter again, approach.

var data = { children: [{ children: [{ children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }, { children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }, { children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }] }, { children: [{ children: [{ name: 'item1' }] }, { children: [{ name: 'item1' }] }, { children: [{ name: 'item1' }] }] }, { children: [{ children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }, { children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }, { children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }] }] }] },
    children = [data].reduce(function iter(r, a) {
        if (Array.isArray(a.children)) {
            return a.children.reduce(iter, r);
        }
        r.push(a);
        return r;
    }, []);

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

Upvotes: 7

cyr_x
cyr_x

Reputation: 14257

You can achieve it with recursion.

var data = {
  children: [
    {
      children: [
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        },
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        },
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        }
      ]
    },
    {
      children: [
        {
          children: [{ name: 'item1' }]
        },
        {
          children: [{ name: 'item1' }]
        },
        {
          children: [{ name: 'item1' }]
        }
      ]
    },
    {
      children: [
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        },
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        },
        {
          children: [{ name: 'item1' }, { name: 'item2' }, { name: 'item3' }]
        }
      ]
    }
  ]
};


function getAllChildren(group, children) {
  children = children || [];
  if(group && Array.isArray(group.children)) {
    group.children.forEach(function(child) { 
      getAllChildren(child, children)
    });
  }
  else {
    children.push(group);
  }
  return children;
}

console.log(getAllChildren(data));

Upvotes: 2

Related Questions