0

Please note this not a duplicate Q.

I have a hard time figuring out the way to go from this JSON array, which is one level array and we can have the path of each obj or element in the "path" property

[
  {
    "name" : "a-1",
    "path" : "a-1",
    "parent": ""
  },
  {
    "name" : "a-2",
    "path" : "a-1>a-2",
    "parent": "a-1"
  },
  {
    "name" : "a-3",
    "path" : "a-1>a-2>a-3",
    "parent": "a-2"
  },
  {
    "name" : "a-4",
    "path" : "a-1>a-4",
    "parent": "a-1"
  },
  {
    "name" : "b-1",
    "path" : "b-1",
    "parent": ""
  }
]

The final result should be as it follow,

[
  {
    "attr": {
      "name": "a-1",
      "path": "a-1",
      "parent": ""
    },
    "children": [
      {
        "attr": {
          "name": "a-2",
          "path": "a-1>a-2",
          "parent": "a-1"
        },
        "children": [
          {
            "attr": {
              "name": "a-3",
              "path": "a-1>a-2>a-3",
              "parent": "a-2"
            }
          }
        ]
      },
      {
        "attr": {
          "name": "a-4",
          "path": "a-1>a-4",
          "parent": "a-1"
        }
      }
    ]
  },
  {
    "attr": {
      "name": "b-1",
      "path": "b-1",
      "parent": ""
    }
  }
]

I tried the to do so using the the parent with the Filter and find function

theOneLevelArray.filter((elt, idx, arr) => {
   let parent = arr.find(e => e.componentItemNumber === elt.parentItemNumber);
   if (!parent) return true;
          (parent.children = parent.children || []).push(elt);
});

I tried also using a loop then applying a reduce function after 'split(">")' the path element (the code is really messy for this method this is why I didn't paste)

huysentruitw
  • 27,376
  • 9
  • 90
  • 133

2 Answers2

1

For using the given path, you could take an iterative approach by checking the given path and the temporary result.

This requires ordered data.

var data = [{ name: "a-1", path: "a-1", parent: "" }, { name: "a-2", path: "a-1>a-2", parent: "a-1" }, { name: "a-3", path: "a-1>a-2>a-3", parent: "a-2" }, { name: "a-4", path: "a-1>a-4", parent: "a-1" }, { name: "b-1", path: "b-1", parent: "" }],
    tree = [];

data.forEach(function (object) {
    object.path.split('>').reduce(function (level, key) {
        var temp = level.find(({ attr: { name } }) => key === name);
        if (!temp) {
            temp = { attr: object, children: [] };
            level.push(temp);
        }
        return temp.children;
    }, tree);
});

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

Another approach by using the parent property and a temporary obejct as reference to the object with the same name.

This works for unsorted data as well.

var data = [{ name: "a-1", path: "a-1", parent: "" }, { name: "a-2", path: "a-1>a-2", parent: "a-1" }, { name: "a-3", path: "a-1>a-2>a-3", parent: "a-2" }, { name: "a-4", path: "a-1>a-4", parent: "a-1" }, { name: "b-1", path: "b-1", parent: "" }],
    tree = function (data, root) {
        var r = [], o = {};
        data.forEach(function (attr) {
            var temp = { attr };
            if (o[attr.name] && o[attr.name].children) {
                temp.children = o[attr.name] && o[attr.name].children;
            }
            o[attr.name] = temp;
            if (attr.parent === root) {
                r.push(temp);
            } else {
                o[attr.parent] = o[attr.parent] || {};
                o[attr.parent].children = o[attr.parent].children || [];
                o[attr.parent].children.push(temp);
            }
        });
        return r;
    }(data, '');

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

Simple recursive approach:

function getNodes(parentName) {
  const mapNode = (node) => {
    const children = getNodes(node.name);
    return children.length > 0 ?
      { attr: node, children } :
      { attr: node };
  };

  return source
     .filter(n => n.parent === parentName)
     .map(mapNode);
}

Invocation: getNodes('')

It's assumed that source is the original array.

oryol
  • 5,178
  • 2
  • 23
  • 18