首页 > 解决方案 > How to organize array of objects into themselves by id

问题描述

I have an array of objects. Those objects can be root or list element (elements of a tree structure). How can I loop through that array to organize those elements into a tree (objects have property of their parent element - id) with the depth of n (not known)?

I'm trying to build (menu). I have successfully organized list elements into their parents. But I'm stuck at putting all root elements into their parents (or root). Problem that I'm having is doing it without nesting loops (checking when everything is organized).

Example of starting data: https://pastebin.com/eCSZ1HgR

[
    {
     "groupId": 1,
     "parentGroupId": null
    },
    {
     "groupId": 3,
     "parentGroupId": 1
    }, ...
]

If objects parentGroupId is null, means that it's in the root of a tree.

Currently I'm working with this code:

for (var i = 0; i < groups.length; i++) {
  var childGroup = groups[i];

  if (childGroup.parentGroupId === null) {
    continue;
  }

  for (var j = 0; j < groups.length; j++) {
    var parentGroup = groups[j];

    if (childGroup.parentGroupId === parentGroup.groupId) {
      if (parentGroup.hasOwnProperty('children')) {
        parentGroup.children.push(childGroup);
      } else {
        parentGroup.children = [childGroup];
      }

      break;
    }
  }
}

标签: javascriptarrays

解决方案


这是一种进行深度复制的方法:

const testInput = [
    {
     "groupId": 1,
     "parentGroupId": null
    },
    {
     "groupId": 3,
     "parentGroupId": 1
    },
    {
      "groupId": 4,
      "parentGroupId": 3
    },
    {
      "groupId": 5,
      "parentGroupId": 1
    }
];

function flatToTree(flatList, idPropName, parentPropName, childrenPropName) {

    const list = [];
    const listIndex = {};

    /* Copy the array and create an index */

    flatList.forEach(listItem => {
      const objectCopy = Object.assign({}, listItem);
      list.push(objectCopy);
      listIndex[listItem[idPropName]] = objectCopy;
    });

    /* Assign children */

    list.forEach(listItem => {
      if (listItem[parentPropName]) {
        const parent = listIndex[listItem[parentPropName]];
        if (Array.isArray(parent[childrenPropName])) {
          parent[childrenPropName].push(listItem);
        }
        else {
          parent[childrenPropName] = [listItem];
        }
      }
    });

    /* Pick the root elements */

    return list.filter(listItem => listItem[parentPropName] === null);
}

const testOutput = flatToTree(testInput, "groupId", "parentGroupId", "children");

推荐阅读