Skip to content

Instantly share code, notes, and snippets.

@alonronin
Last active August 26, 2023 09:23
Show Gist options
  • Save alonronin/2592a6a81db67804db1f to your computer and use it in GitHub Desktop.
Save alonronin/2592a6a81db67804db1f to your computer and use it in GitHub Desktop.
Create recursive tree from json using lodash transform without recursion. Can have unlimited nesting.
var _ = require('lodash');
var arr = [
{"name":"my2child1","title":"My 2 Child 1","parent":"my2"},
{"name":"my2child2","title":"My 2 Child 2","parent":"my2"},
{"name":"parent","title":"A single parent"},
{"name":"child-parent","title":"A child parent","parent":"child1"},
{"name":"my","title":"My"},
{"name":"my2","title":"My2"},
{"name":"child1","title":"Child 1","parent":"my"},
{"name":"child2","title":"Child 2","parent":"my"}
];
var result = _.filter(arr, function(item){
var parentName = item.parent;
item.children = this(item.name);
return !(parentName && this(parentName).push(item));
}, _.memoize(function(){ return []; }));
console.log(JSON.stringify(result, null, 2));
// ==> output
//[
// {
// "name": "parent",
// "title": "A single parent",
// "children": []
// },
// {
// "name": "my",
// "title": "My",
// "children": [
// {
// "name": "child1",
// "title": "Child 1",
// "parent": "my",
// "children": [
// {
// "name": "child-parent",
// "title": "A child parent",
// "parent": "child1",
// "children": []
// }
// ]
// },
// {
// "name": "child2",
// "title": "Child 2",
// "parent": "my",
// "children": []
// }
// ]
// },
// {
// "name": "my2",
// "title": "My2",
// "children": [
// {
// "name": "my2child1",
// "title": "My 2 Child 1",
// "parent": "my2",
// "children": []
// },
// {
// "name": "my2child2",
// "title": "My 2 Child 2",
// "parent": "my2",
// "children": []
// }
// ]
// }
//]
@alonronin
Copy link
Author

@tweinfeld solution:

function transformToTree(arr){
    var nodes = {};    
    return arr.filter(function(obj){
        var id = obj["name"],
            parentId = obj["parent"];

        nodes[id] = _.defaults(obj, nodes[id], { children: [] });
        parentId && (nodes[parentId] = (nodes[parentId] || { children: [] }))["children"].push(obj);

        return !parentId;
    });    
}

var arr = [
    {"name":"my2child1","title":"My 2 Child 1","parent":"my2"},
    {"name":"my2child2","title":"My 2 Child 2","parent":"my2"},
    {"name":"parent","title":"A single parent"},
    {"name":"child-parent","title":"A child parent", "parent": "child1"},
    {"name":"my","title":"My"},
    {"name":"my2","title":"My2"},
    {"name":"child1","title":"Child 1","parent":"my"},
    {"name":"child2","title":"Child 2","parent":"my"}
];

var result = transformToTree(arr);

console.log(JSON.stringify(result, null, 2));

@alonronin
Copy link
Author

update it to be more functional using one iteration inspired by Tal Weinfeld.

@alonronin
Copy link
Author

update to be even more functional, thanx Tal 😄

@yogendra9891
Copy link

[
{
"name": "parent",
"title": "A single parent",
"children": []
},
{
"name": "my",
"title": "My",
"children": [
{
"name": "child1",
"title": "Child 1",
"parent": "my",
"children": [
{
"name": "child-parent",
"title": "A child parent",
"parent": "child1",
"children": []
}
]
},
{
"name": "child2",
"title": "Child 2",
"parent": "my",
"children": []
}
]
},
{
"name": "my2",
"title": "My2",
"children": [
{
"name": "my2child1",
"title": "My 2 Child 1",
"parent": "my2",
"children": []
},
{
"name": "my2child2",
"title": "My 2 Child 2",
"parent": "my2",
"children": []
}
]
}
]

this is my json

I need all parents name of a each node.

@MrEldin
Copy link

MrEldin commented Jul 4, 2018

Hi @alonronin, i tried this one, and I got error:

"this is not a function"

What I'm doing wrong?

@alonronin
Copy link
Author

@MrEldin it was with lodash 3, need to refactor to 4 remove the this or use bind.

@samvirkar144
Copy link

Hi @alonronin, @MrEldin ,Is there any external library or npm package that can handle very large files (Millions json object in array) by passing specific column. Thank you...

@tanveerbyn
Copy link

@LFTroya
Copy link

LFTroya commented Jul 29, 2019

_.defaults

I think you could replace _.defaults with Object.assign() and remove lodash dependency

@stzach
Copy link

stzach commented Feb 19, 2021

Hello,

Looking to enhance your functionality with ordering and also create the opposite tree2recursive function.

var arr = [
{ id: "0", title: "ROOT", parentId: "", order: 1 },
{ id: "30", title: "My 2 Child 1", parentId: "3", order: 2 },
{ id: "31", title: "My 2 Child 2", parentId: "3", order: 1 },
{ id: "1", title: "A single parent", parentId: "0", order: 3 },
{ id: "200", title: "A child parent", parentId: "20", order: 1 },
{ id: "2", title: "My", parentId: "0", order: 1 },
{ id: "3", title: "My2", parentId: "0", order: 2 },
{ id: "20", title: "Child 1", parentId: "2", order: 2 },
{ id: "21", title: "Child 2", parentId: "2", order: 1 }
];

So the arr item is having order so all items are order in the tree children property. Also maybe there is a ROOT element, but this is not important as you can easily add it later on. Any thoughts on that?

Copy link

ghost commented Jun 23, 2022

First, you need install loash with below command with npm:

npm i lodash

Second, you must import _ from loash

import _ from "lodash";

Finally, run this function:

export const recursive_lists = (data) => {
  const grouped = _.groupBy(data, (item) => item. parent_id);

  function childrenOf(parent_id) {
    return (grouped[parent_id] || []).map((item) => ({
      id: item.id,
      title: item.title,
      child: childrenOf(item.id),
    }));
  }

  return childrenOf(null);
};

or

First:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>

Second:

function recursive_lists(data) {
  const grouped = _.groupBy(data, (item) => item.parent_id);

  function childrenOf(parent_id) {
    return (grouped[parent_id] || []).map((item) => ({
      id: item.id,
      title: item.title,
      child: childrenOf(item.id),
    }));
  }

  return childrenOf(null);
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment