【问题标题】:How to convert flat array of objects (with possibly multiple parents) into a nested array of objects如何将平面对象数组(可能有多个父对象)转换为嵌套对象数组
【发布时间】:2019-12-02 10:05:18
【问题描述】:

我有一组通过 parentId 相互链接的任务。但是,任何任务都可能有多个父级。因此不一定是简单的单树层次结构。我想要实现的是代替父母[],我想有一个孩子[]。但是,我似乎无法理解如何递归地处理这个问题。任何帮助将不胜感激。

这是平面 JSON 数组

[
  {
    "_id": "4b04e450-06d5-4453-8d50-d3b2a70d9b2d",
    "task_name": "Parent2",
    "parents": []
  },
  {
    "_id": "a15ca08e-f13b-4d73-a496-ba23832ea233",
    "task_name": "Endpoints",
    "parents": [
      {
        "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
        "task_name": "Parent1"
      },
      {
        "_id": "4b04e450-06d5-4453-8d50-d3b2a70d9b2d",
        "task_name": "Parent2"
      }
    ]
  },
  {
    "_id": "ee78316a-491e-4db5-8f82-13b12b5b86fc",
    "task_name": "Mapping",
    "parents": [
      {
        "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
        "task_name": "Parent1"
      }
    ]
  },
  {
    "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
    "task_name": "Parent1",
    "parents": []
  }
]

我想要实现的是以下

[
  {
    "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
    "task_name": "Parent1",
    "children": [
      {
        "_id": "ee78316a-491e-4db5-8f82-13b12b5b86fc",
        "task_name": "Mapping",
        "children": []
      },
      {
        "_id": "a15ca08e-f13b-4d73-a496-ba23832ea233",
        "task_name": "Endpoints",
        "children": []
      }
    ]
  },
  {
    "_id": "4b04e450-06d5-4453-8d50-d3b2a70d9b2d",
    "task_name": "Parent2",
    "children": [
      {
        "_id": "a15ca08e-f13b-4d73-a496-ba23832ea233",
        "task_name": "Endpoints",
        "children": []
      }
    ]
  }
]

我尝试过的

function transform(list, idAttr, parentAttr, childrenAttr) {
    if (!idAttr) idAttr = '_id';
    if (!parentAttr) parentAttr = 'parents';
    if (!childrenAttr) childrenAttr = 'children';

    var newArr = [];
    var lookup = {};
    list.forEach(function(obj) {
        lookup[obj[idAttr]] = obj;
        obj[childrenAttr] = [];
    });
    list.forEach(function(obj) {
        if (obj[parentAttr] != null) {
            lookup[obj[parentAttr]][childrenAttr].push(obj);
        } else {
            newArr.push(obj);
        }
    });
    return newArr;
};

如果原始数组中的 parent 键等于任务的 _id,则此方法可以正常工作。但是,我不确定如何让它适用于具有对象数组作为值的父键。

【问题讨论】:

  • 嗨!请使用tour(您将获得徽章!)并通读help center,尤其是How do I ask a good question? 您最好的选择是进行研究,search 以获取有关 SO 的相关主题,然后试一试. 如果您在进行更多研究和搜索后遇到困难并且无法摆脱困境,请发布您的尝试minimal reproducible example,并具体说明您遇到的问题。人们会很乐意提供帮助。
  • 您将如何实现这一目标?基于什么 ?不清楚。
  • 请发布您的解决方案方法,该方法可以修改为工作版本,以查看您的基础和您想要实现的目标。
  • 为什么一个节点有两个父节点?我的意思是实际上是的,但作为一个抽象的数据结构?第二个父母要去哪里,孩子们会发生什么?
  • @J.Knabenschuh 我已经用我的“解决方案”努力更新了我的问题。

标签: javascript arrays parent-child


【解决方案1】:

您可以使用_id 作为键的对象,并存储父母以及他们的关系。最后取出没有父母的物品的孩子。

var data = [{ _id: "4b04e450-06d5-4453-8d50-d3b2a70d9b2d", task_name: "Parent2", parents: [] }, { _id: "a15ca08e-f13b-4d73-a496-ba23832ea233", task_name: "Endpoints", parents: [{ _id: "97bbf892-8a2a-4f45-befd-4fdbebded04b", task_name: "Parent1" }, { _id: "4b04e450-06d5-4453-8d50-d3b2a70d9b2d", task_name: "Parent2" }] }, { _id: "ee78316a-491e-4db5-8f82-13b12b5b86fc", task_name: "Mapping", parents: [{ _id: "97bbf892-8a2a-4f45-befd-4fdbebded04b", task_name: "Parent1" }] }, { _id: "97bbf892-8a2a-4f45-befd-4fdbebded04b", task_name: "Parent1", parents: [] }],
    tree = function (data, root) {
        var t = {};
        data.forEach(({ parents, ...o }) => {
            Object.assign(t[o._id] = t[o._id] || {}, o);
            if (!parents.length) {
                t[root] = t[root] || {};
                t[root].children = t[root].children || [];
                t[root].children.push(t[o._id]);
                return;
            }
            parents.forEach(p => {
                Object.assign(t[p._id] = t[p._id] || {}, p);
                t[p._id].children = t[p._id].children || [];
                t[p._id].children.push(t[o._id]);
            });
        });
        return t[root].children;
    }(data);

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

【讨论】:

  • 谢谢你这是完美的!!
【解决方案2】:

您可以保持扁平的 JSON 数组结构并只存储 ID 以进行交叉引用,就像这样(ID 只是示例)

    [
        {
            "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
            "task_name": "Task1",
            "children": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ],
            "parents": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ]
        },
        {
            "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
            "task_name": "Task2",
            "children": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ],
            "parents": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ]
        },
        {
            "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
            "task_name": "Task3",
            "children": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ],
            "parents": [
                "ee78316a-491e-4db5-8f82-13b12b5b86fc",
                "a15ca08e-f13b-4d73-a496-ba23832ea233"
            ]
        }
    ]

或者,如果您想以您当前希望的方式实现它,您可以使用此功能。没有完全测试,但你明白了

var tasks =     [
  {
    "_id": "4b04e450-06d5-4453-8d50-d3b2a70d9b2d",
    "task_name": "Parent2",
    "parents": []
  },
  {
    "_id": "a15ca08e-f13b-4d73-a496-ba23832ea233",
    "task_name": "Endpoints",
    "parents": [
      {
        "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
        "task_name": "Parent1"
      },
      {
        "_id": "4b04e450-06d5-4453-8d50-d3b2a70d9b2d",
        "task_name": "Parent2"
      }
    ]
  },
  {
    "_id": "ee78316a-491e-4db5-8f82-13b12b5b86fc",
    "task_name": "Mapping",
    "parents": [
      {
        "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
        "task_name": "Parent1"
      }
    ]
  },
  {
    "_id": "97bbf892-8a2a-4f45-befd-4fdbebded04b",
    "task_name": "Parent1",
    "parents": []
  }
];

function transformTasks(tasks){
    var transformed = {};
    var transformedAsArray = [];
    for(var taskIndex in tasks){
        var task = tasks[taskIndex];
        if(transformed[task["_id"]] === undefined){
            transformed[task["_id"]] = {_id:task["_id"],task_name:task["task_name"],children:[]};
            transformedAsArray.push(transformed[task["_id"]]);
        }
        for(var parentIndex in task["parents"]){
            var parentTask = task["parents"][parentIndex];
            if(transformed[parentTask["_id"]] === undefined){
                transformed[parentTask["_id"]] = {_id:parentTask["_id"],task_name:parentTask["task_name"],children:[]};
                transformedAsArray.push(transformed[parentTask["_id"]]);
            }
            transformed[parentTask["_id"]].children.push(transformed[task["_id"]]);

        }
    }

    return transformedAsArray;
}

console.log(transformTasks(tasks));

【讨论】:

  • 不幸的是,我无权访问存储数据,只能操作已经存在的数据。感谢您的回复。
  • 检查编辑到上一个答案末尾的替代解决方案
猜你喜欢
  • 2020-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-26
  • 2021-05-28
  • 1970-01-01
  • 2020-07-03
相关资源
最近更新 更多