0

I have a JSON that is :

var json = [{
  "name": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
  "parent": "null"
}, {
  "name": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40",
  "parent": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f"
}, {
  "name": "0x8fa01b60f503a3873c1b02ef351112f57cdd818e",
  "parent": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40"
}, {
  "name": "0x753a018eca49f1b1e8b46b88d6a7b449478740e0",
  "parent": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f"
}]

I'm trying to using Javascript to rewrite this into a new JSON that would be ordered like:

var json = [{
  "name": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
  "parent": "null",
  "children": [{
    "name": "0x753a018eca49f1b1e8b46b88d6a7b449478740e0",
    "parent": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f"
  }, {
    "name": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40",
    "parent": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
    "children": [{
      "name": "0x8fa01b60f503a3873c1b02ef351112f57cdd818e",
      "parent": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40"
    }]
  }]
}]

Children would be created and nested to their parent object. Each name is unique, first object have no parent ("null"), and it's possible an object don't have children ("null" or empty array []).

I'm not used to javascript and I'm not sure how exactly I can achieve that, I tried various loop but not working, as :

 json.forEach(function(link) {
    var parent = link.parent = nodeByName(json,link.parent),
        child = link.children = nodeByName(json,link.children);
    if (parent.children) parent.children.push(child);
    else parent.children = [child];
  });

But this result as :

[{
  "name": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
  "parent": {
    "name": "null",
    "children": [{}]
  },
  "children": {}
}, {
  "name": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40",
  "parent": {
    "name": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
    "children": [{}, {}]
  },
  "children": {}
}, {
  "name": "0x8fa01b60f503a3873c1b02ef351112f57cdd818e",
  "parent": {
    "name": "0xe8f84d8ad5850d66bd289ce3199753c35f4cbf40",
    "children": [{}]
  },
  "children": {}
}, {
  "name": "0x753a018eca49f1b1e8b46b88d6a7b449478740e0",
  "parent": {
    "name": "0xcd963fe5b4d9de5380130d6c6b6cfb5d3b903b1f",
    "children": [{}, {}]
  },
  "children": {}
}]
mhodges
  • 10,938
  • 2
  • 28
  • 46
btc4cash
  • 375
  • 1
  • 4
  • 15
  • 2
    Super important note: the first bit of code you show is _not_ JSON at all. It's a plain JS array containing plain JS objects. It sounds like your question has nothing to do with JSON, which is pure string data, and everything to do with sorting an array. In which case, use the `.sort()` function with a custom sort function as argument. – Mike 'Pomax' Kamermans Feb 05 '20 at 22:19
  • @Mike'Pomax'Kamermans will check .sort and let you know :) – btc4cash Feb 05 '20 at 22:28
  • 1
    @Mike'Pomax'Kamermans While your statement about it not being true JSON is correct, this has nothing to do with sorting.. – mhodges Feb 05 '20 at 22:33
  • 1
    Does this answer your question? [Build tree array from flat array in javascript](https://stackoverflow.com/questions/18017869/build-tree-array-from-flat-array-in-javascript) – blex Feb 05 '20 at 22:34
  • 1
    Solution above applied to your use case: https://jsfiddle.net/4wfkm2u1/ _(Note: it **will** mutate your original Array. If you don't want that, [create a copy of it](https://stackoverflow.com/a/23481096/1913729) first.)_ – blex Feb 05 '20 at 22:39
  • @blex you rock a lot. It's working :) You also made me understand that I was looking up information with the wrong terms., too specific. Much appreciated! – btc4cash Feb 05 '20 at 22:49
  • @blex put as answer and I'll gladly accept – btc4cash Feb 05 '20 at 22:50

2 Answers2

2

You can use reduce(), combined with a recursive function (to support many nested children levels):

function getChildren (name, items) {
  return items
    .filter(({ parent }) => parent === name)
    .map(item => ({...item, children: getChildren(item.name, json)}));
}

const resultAsObject = json.reduce((accum, {name, parent}) => {
  if (parent === "null") {
    accum[name] = { name, parent, children: getChildren(name, json) };
  }
  return accum;
}, {});

const resultAsArray = Object.values(resultAsObject);
sgmonda
  • 2,615
  • 1
  • 19
  • 29
  • @blex solution made it before I read yours, and I've got this with your solution jQuery.Deferred exception: resultAsObject is not a function which I guess this is just related to my code – btc4cash Feb 05 '20 at 22:51
  • 1
    @btc4cash: if Blex adds an answer, by all means do reward them. However, sometimes people just put a quick comment because they don't have the time or inclination to make an answer, and in those circumstances it is considered OK to accept the best answer posted. – halfer Feb 05 '20 at 23:01
  • I didn't post an answer because I voted to close this question as a duplicate :) – blex Feb 05 '20 at 23:05
0

As @blex mentioned in a comment, this function did exactly what I needed to achieve. Thanks a lot!

This is an adaptation of this answer: Build tree array from flat array in javascript

function list_to_tree(list) {
    var map = {}, node, roots = [], i;
    for (i = 0; i < list.length; i += 1) {
        map[list[i].name] = i;
    }
    for (i = 0; i < list.length; i += 1) {
        node = list[i];
        if (node.parent !== "null") {
            var parent = list[map[node.parent]];
            if (!parent.children) {
              parent.children = [];
            }
            parent.children.push(node);
        } else {
            roots.push(node);
        }
    }
    return roots;
}

var res = list_to_tree(json)
blex
  • 24,941
  • 5
  • 39
  • 72
btc4cash
  • 375
  • 1
  • 4
  • 15