0

I'm trying to manipulate this sample array of objects.

var data = [
  { id: 'A', name: 'Test1', parentId: null },
  { id: 'B', name: 'Test2', parentId: 'A'},
  { id: 'C', name: 'Test3', parentId: 'A'},
  { id: 'D', name: 'Test4', parentId: null },
  { id: 'E', name: 'Test5', parentId: 'D'},
  { id: 'F', name: 'Test6', parentId: 'D'},
];

What I need to do is to map array to array like that

var data = [
  {
    id: 'A', 
    name: 'Test1', 
    parentId: null, 
    children:[
      { id: 'B', name: 'Test2', parentId: 'A'},
      { id: 'C', name: 'Test3', parentId: 'A'}
    ],
  },
  {
    id: 'D', 
    name: 'Test4', 
    parentId: null, 
    children:[
      { id: 'E', name: 'Test5', parentId: 'D'},
      { id: 'F', name: 'Test6', parentId: 'D'}
    ],
  },
];

What is the simplest way to do that, using lodash? Please help me.

Thien Vu
  • 61
  • 1
  • 8
  • 1
    Possible duplicate of [Lodash mapping of nested collections](https://stackoverflow.com/questions/49553159/lodash-mapping-of-nested-collections) – StefanN May 10 '19 at 07:49
  • Almost an exact dupe, but with plain JS (no lodash): [Construct hierarchy tree from flat list with parent field?](https://stackoverflow.com/questions/22367711/construct-hierarchy-tree-from-flat-list-with-parent-field) (though, TBH, there's no need for lodash at all) – Amadan May 10 '19 at 07:50

4 Answers4

0

_.groupBy is more effective in such scenarios. You need to group the elements by parentId, so that you can easily assign their children later.

var data = [
  { id: 'A', name: 'Test1', parentId: null },
  { id: 'B', name: 'Test2', parentId: 'A'},
  { id: 'C', name: 'Test3', parentId: 'A'},
  { id: 'D', name: 'Test4', parentId: null },
  { id: 'E', name: 'Test5', parentId: 'D'},
  { id: 'F', name: 'Test6', parentId: 'D'},
];

var map = _.groupBy(data, 'parentId');
map[null].forEach(item => item.children = map[item.id]);
console.log(map[null]);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
31piy
  • 23,323
  • 6
  • 47
  • 67
0

You can do this using reduce method and create nested structure for any depth level.

var data = [{ id: 'A', name: 'Test1', parentId: null },{ id: 'B', name: 'Test2', parentId: 'A'},{ id: 'C', name: 'Test3', parentId: 'A'},{ id: 'D', name: 'Test4', parentId: null },{ id: 'E', name: 'Test5', parentId: 'D'},{ id: 'F', name: 'Test6', parentId: 'D'}];

function tree(data, parentId = null) {
  return _.reduce(data, (r, e) => {
    if (parentId == e.parentId) {
      const o = _.clone(e);
      const children = tree(data, e.id);
      if (children.length) o.children = children;
      r.push(o)
    }
    return r;
  }, [])
}

const result = tree(data);
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
0

The usage of _.groupBy is the closest to your needs, just select parentId as previously said. If you need it to be recursive, you could try something like this:

var data = [
  { id: 'A', name: 'Test1', parentId: null },
  { id: 'B', name: 'Test2', parentId: 'A'},
  { id: 'C', name: 'Test3', parentId: 'A'},
  { id: 'D', name: 'Test4', parentId: null },
  { id: 'E', name: 'Test5', parentId: 'B'},
  { id: 'F', name: 'Test6', parentId: 'D'},
];

function assignChildrens(grouped, parentId) {
    if (!grouped[parentId]) return [];
    return _.map(grouped[parentId], v => {
        v.childrens = assignChildrens(grouped, v.id);
        return v;
    });
}

var finalData = assignChildrens(_.groupBy(data, 'parentId'), null);

That way, you could have nested elements and still works.

danpeis
  • 166
  • 6
0

You could take a single loop approach which takes the relation between children and parent and parents and children into a hash table and resturns only the children of the given root nodes.

var data = [{ id: 'A', name: 'Test1', parentId: null }, { id: 'B', name: 'Test2', parentId: 'A'}, { id: 'C', name: 'Test3', parentId: 'A'}, { id: 'D', name: 'Test4', parentId: null }, { id: 'E', name: 'Test5', parentId: 'D'}, { id: 'F', name: 'Test6', parentId: 'D'}],
    tree = function(data, root) {
        var t = {};
        data.forEach(o => {
            Object.assign(t[o.id] = t[o.id] || {}, o);
            t[o.parentId] = t[o.parentId] || { id: o.parentId };
            t[o.parentId].children = t[o.parentId].children || [];
            t[o.parentId].children.push(t[o.id]);
        });
        return t[null].children;
    }(data, null);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392