JavaScript:将具有父键的对象数组转换为父/子树(包括没有父对象的对象)

时间:2018-10-02 12:01:31

标签: javascript arrays object spread-syntax

我有一个带有父键的对象列表,这些对象描述了嵌套的父/子关系的多个级别。

const table =[
    {
        "id": 791,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {
        "id": 790,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {
        "id": 845,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 844,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {   
        "id": 802,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 788,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 863,
        "sortOrder": 0,
        "parentCategoryId": 863
    },
    {    
        "id": 858,
        "sortOrder": 0,
        "parentCategoryId": 858
    },
    {    
        "id": 867,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 871,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 801,
        "name": "Tickets",
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 792,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 797,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 789,
        "name": "Hot food",
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 798,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 671,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 833,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 796,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 843,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {    
        "id": 840,
        "sortOrder": 0,
        "parentCategoryId": 793
    },
    {    
        "id": 868,
        "sortOrder": 0,
        "parentCategoryId": 868
    },
    {    
        "id": 851,
        "sortOrder": 0,
        "parentCategoryId": 851
    },
    {    
        "id": 839,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 793,
        "sortOrder": 0,
        "parentCategoryId": 839
    },
    {    
        "id": 859,
        "sortOrder": 0,
        "parentCategoryId": 859
    },
    {   
        "id": 805,
        "sortOrder": 0,
        "parentCategoryId": 859
    },
    {    
        "id": 856,
        "name": "DRINKS",
        "sortOrder": 0,
        "parentCategoryId": 805
    },
    {    
        "id": 870,
        "sortOrder": 0,
        "parentCategoryId": 856
    },
    {    
        "id": 787,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 786,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 799,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 852,
        "sortOrder": 0,
        "parentCategoryId": 852
    },
    {    
        "id": 795,
        "name": "Gents fragrance",
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 864,
        "sortOrder": 0,
        "parentCategoryId": 864
    },
    {   
        "id": 854,
        "sortOrder": 0,
        "parentCategoryId": 854
    },
    {    
        "id": 865,
        "sortOrder": 0,
        "parentCategoryId": 865
    },
    {    
        "id": 869,
        "name": "GFI",
        "sortOrder": 0,
        "parentCategoryId": 869
    },
    {    
        "id": 785,
        "sortOrder": 0,
        "parentCategoryId": 833
    }
]

问题是我没有一个根父ID为0。我想在一个数组中对其进行排序,该数组在idparentCategoryId匹配的第一级项目中显示,这意味着它们是每个人的根,比每个人都有孩子。

这是我走了多远,但是努力做到这一点:

var root = { cid: 0, parent_id: null, children: []};
var node_list = { 0 : root};

     for (var i = 0; i < table.length; i++) {

       console.log('updated list', node_list)
       console.log('item in cat', table[i])

       // check if parent ID exsits in the list
       if (!node_list[table[i].parentCategoryId]) {

         console.log('not in the list');
         console.log('node_list[table[i].parentCategoryId]', table[i].parentCategoryId)
         if (table[i].parentCategoryId === table[i].cid) {
           console.log('it is the root');
           node_list[table[i].cid] = table[i];
         }    

       } else {

         const item = table[i];
         console.log('item is ', item)

         node_list[table[i].parentCategoryId].children = {
           ...node_list[table[i].parentCategoryId].children,
           ...item
         };
       }
     }

预期结果:

const table =[
    {  
        "id": 791,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 790,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 845,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 844,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {    
        "id": 802,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 788,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 863,
        "sortOrder": 0,
        "parentCategoryId": 863
    },
    {    
        "id": 858,
        "sortOrder": 0,
        "parentCategoryId": 858
    },
    {    
        "id": 867,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 871,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 801,
        "sortOrder": 0,
        "parentCategoryId": 847
    },    
    {    
        "id": 797,
        "sortOrder": 0,
        "parentCategoryId": 847,
        children:[
            {    
                "id": 792,
                "sortOrder": 0,
                "parentCategoryId": 797,
                children:[
                    {
                        "id": 671,
                        "sortOrder": 0,
                        "parentCategoryId": 792
                    },
                ]
            },
        ]
    },
    {    
        "id": 789,
        "name": "Hot food",
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 798,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 833,
        "sortOrder": 0,
        "parentCategoryId": 833,
        children:[
            {    
                "id": 785,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
            {
                "id": 786,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
            {
                "id": 787,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
        ]
    },
    {   
        "id": 796,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 843,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {   
        "id": 840,
        "sortOrder": 0,
        "parentCategoryId": 793
    },
    {    
        "id": 868,
        "sortOrder": 0,
        "parentCategoryId": 868
    },
    {    
        "id": 851,
        "sortOrder": 0,
        "parentCategoryId": 851
    },
    {    
        "id": 839,
        "sortOrder": 0,
        "parentCategoryId": 847,
        children:[
            {
                "id": 793,
                "sortOrder": 0,
                "parentCategoryId": 839,
                children:[
                    {    
                        "id": 870,
                        "sortOrder": 0,
                        "parentCategoryId": 856
                    },
                ]
            },
        ]
    },
    {    
        "id": 805,
        "sortOrder": 0,
        "parentCategoryId": 859,
        children:[
            {
                "id": 856,
                "sortOrder": 0,
                "parentCategoryId": 805
            },
            {    
                "id": 859,
                "sortOrder": 0,
                "parentCategoryId": 805
            },
        ]
    },      
]

2 个答案:

答案 0 :(得分:1)

好像您想向初始数组中的对象添加带有值数组的children键,其中id值对应于其他对象中的一个或多个parentCategoryId值在数组中-并且不应在嵌套对象数组中将任何对象作为父对象或子对象重复。

您可以map数组以附加子项,然后filter仅返回根父母(和孤儿)。例如(如果要查看输出,请在示例下面的工作片段):

const ids = table.map(x => x.id);

let result = table.map((parent) => {
  let children = table.filter((child) => {
    if (child.id !== child.parentCategoryId && child.parentCategoryId === parent.id) {
      return child;
    }
  });
  if (children.length) {
    parent.children = children;
  }
  return parent;
}).filter((obj) => {
  if (obj.id === obj.parentCategoryId || !ids.includes(obj.parentCategoryId)) {
    // include ultimate parents and orphans at root
    return obj;
  }
});

const table = [{
    "id": 791,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 790,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 845,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 844,
    "sortOrder": 0,
    "parentCategoryId": 842
  },
  {
    "id": 802,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 788,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 863,
    "sortOrder": 0,
    "parentCategoryId": 863
  },
  {
    "id": 858,
    "sortOrder": 0,
    "parentCategoryId": 858
  },
  {
    "id": 867,
    "sortOrder": 0,
    "parentCategoryId": 867
  },
  {
    "id": 871,
    "sortOrder": 0,
    "parentCategoryId": 867
  },
  {
    "id": 801,
    "name": "Tickets",
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 792,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 797,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 789,
    "name": "Hot food",
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 798,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 671,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 833,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 796,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 843,
    "sortOrder": 0,
    "parentCategoryId": 842
  },
  {
    "id": 840,
    "sortOrder": 0,
    "parentCategoryId": 793
  },
  {
    "id": 868,
    "sortOrder": 0,
    "parentCategoryId": 868
  },
  {
    "id": 851,
    "sortOrder": 0,
    "parentCategoryId": 851
  },
  {
    "id": 839,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 793,
    "sortOrder": 0,
    "parentCategoryId": 839
  },
  {
    "id": 859,
    "sortOrder": 0,
    "parentCategoryId": 859
  },
  {
    "id": 805,
    "sortOrder": 0,
    "parentCategoryId": 859
  },
  {
    "id": 856,
    "name": "DRINKS",
    "sortOrder": 0,
    "parentCategoryId": 805
  },
  {
    "id": 870,
    "sortOrder": 0,
    "parentCategoryId": 856
  },
  {
    "id": 787,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 786,
    "sortOrder": 0,
    "parentCategoryId": 833
  },
  {
    "id": 799,
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 852,
    "sortOrder": 0,
    "parentCategoryId": 852
  },
  {
    "id": 795,
    "name": "Gents fragrance",
    "sortOrder": 0,
    "parentCategoryId": 847
  },
  {
    "id": 864,
    "sortOrder": 0,
    "parentCategoryId": 864
  },
  {
    "id": 854,
    "sortOrder": 0,
    "parentCategoryId": 854
  },
  {
    "id": 865,
    "sortOrder": 0,
    "parentCategoryId": 865
  },
  {
    "id": 869,
    "name": "GFI",
    "sortOrder": 0,
    "parentCategoryId": 869
  },
  {
    "id": 785,
    "sortOrder": 0,
    "parentCategoryId": 833
  }
];

const ids = table.map(x => x.id);

let result = table.map((parent) => {
  let children = table.filter((child) => {
    if (child.id !== child.parentCategoryId && child.parentCategoryId === parent.id) {
      return child;
    }
  });
  if (children.length) {
    parent.children = children;
  }
  return parent;
}).filter((obj) => {
  if (obj.id === obj.parentCategoryId || !ids.includes(obj.parentCategoryId)) {
    // include ultimate parents and orphans at root
    return obj;
  }
});

// stringify just to flatten out SO console result for easier result scanning
console.log(JSON.stringify(result));

答案 1 :(得分:1)

我们有一个复杂的 json 文件,我们必须用 JavaScript 处理它以使其具有层次结构,以便以后构建树。 JSON 数组的每个条目都有 - id - 唯一的 id, parentId - 父节点的 id(如果节点是树的根,则为 0) level - 树中的深度级别。

JSON 数据已经“有序”,这意味着条目将在其自身上方具有父节点或兄弟节点,在其自身下方具有子节点或兄弟节点。

    const arr = [
   {
      "id": "12",
      "parentId": "0",
      "text": "Man",
      "level": "1",
      "children": null
   },
   {
      "id": "6",
      "parentId": "12",
      "text": "Boy",
      "level": "2",
      "children": null
   },
   {
      "id": "7",
      "parentId": "12",
      "text": "Other",
      "level": "2",
      "children": null
   },
   {
      "id": "9",
      "parentId": "0",
      "text": "Woman",
      "level": "1",
      "children": null
   },
   {
      "id": "11",
      "parentId": "9",
      "text": "Girl",
      "level": "2",
      "children": null
   }
];
const listToTree = (arr = []) => {
   let map = {}, node, res = [], i;
   for (i = 0; i < arr.length; i += 1) {
      map[arr[i].id] = i;
      arr[i].children = [];
   };
   for (i = 0; i < arr.length; i += 1) {
      node = arr[i];
      if (node.parentId !== "0") {
         arr[map[node.parentId]].children.push(node);
      }
      else {
         res.push(node);
      };
   };
   return res;
};
console.log(JSON.stringify(listToTree(arr), undefined, 4));