将JSON平放到具有重复节点的层次结构

时间:2016-12-01 12:00:36

标签: javascript arrays object flatten

我正在构建一个平面的分层对象结构。到目前为止,一切都运行良好,但我遇到了共享相同父ID的项目的问题。例如:

{
   'id': 9,
   'parentid': 7
 }, {
   'id': 9,
   'parentid': 8
 }, {
   'id': 10,
   'parentid': 9
 }

根据我的理解,正确的是id为9的项目同时出现在父7和父8之下。同时,id为10的项目出现在id 9的两个实例下。所以,我基本上想要这个:

{
    "id": 7,
    "parentid": 1,
    "children": [
     {
      "id": 9,
      "parentid": 7,
      "children": [
       {
        "id": 10,
        "parentid": 9,
        "children": []
       },
{
    "id": 8,
    "parentid": 1,
    "children": [
     {
      "id": 9,
      "parentid": 8,
      "children": [
       {
        "id": 10,
        "parentid": 9,
        "children": []
       }

但是我得到了这个。当id被分配一次时,该id的可能新外观将被忽略。

  {
    "id": 8,
    "parentid": 1,
    "children": [
     {
      "id": 9,
      "parentid": 8,
      "children": [
       {
        "id": 10,
        "parentid": 9,
        "children": []
       }

这是我正在使用的功能:

 function unflatten(arr) {
   var tree = [],
     mappedArr = {},
     arrElem,
     mappedElem;

   // First map the nodes of the array to an object -> create a hash table.
   for (var i = 0, len = arr.length; i < len; i++) {
     arrElem = arr[i];
     mappedArr[arrElem.id] = arrElem;
     mappedArr[arrElem.id]['children'] = [];
   }


   for (var id in mappedArr) {
     if (mappedArr.hasOwnProperty(id)) {
       mappedElem = mappedArr[id];
       // If the element is not at the root level, add it to its parent array of children.
       if (mappedElem.parentid) {
         mappedArr[mappedElem['parentid']]['children'].push(mappedElem);
       }
       // If the element is at the root level, add it to first level elements array.
       else {
         tree.push(mappedElem);
       }
     }
   }
   return tree;
 }

 var tree = unflatten(arr);

我不明白需要考虑id的所有外观,而不仅仅是第一次。我应该进一步研究哪种想法?

1 个答案:

答案 0 :(得分:1)

拥有一个 id 对象是违反直觉的,但是希望该对象的版本具有 parentid 的一个值,以及 parentid 的另一个值。从逻辑上讲, id 应该标识一个对象,并且一个对象不能同时为同一个属性设置两个不同的值。

请注意这会导致您的代码出错:

mappedArr[arrElem.id] = arrElem;

由于多次出现相同的 id ,您覆盖相同的条目,其中包含您在此处指定的最后一个对象(版本),丢失之前的一个(s)具有 parentid 的其他值。

您应该考虑创建一个复数属性 parentIds ,并为其分配一个父 id 值的数组。这样你就可以保持一个实际上一个对象有多个父母的情况。

请注意,节点不仅可以有多个子节点,而且还有多个父节点的图形不是树(因此您的变量名称具有误导性),而是(定向)图形。

从代码开始,我将其修改为:

&#13;
&#13;
function unflatten(arr) {
    var node,
        graph = [], // it is not a tree
        mapped = [];
    
    // 1. combine nodes with the same id:
    arr.forEach( function (node) {
        (mapped[node.id] || (mapped[node.id] = {
            id: node.id,
            parentIds: [],
            children: []
        })).parentIds.push(node.parentid);
    });
    
    // 2. assign children:
    mapped.forEach(function (node) {
        // Add as child to each of the parents 
        node.parentIds.forEach(function (parentid) {
            if (mapped[parentid]) {
                mapped[parentid]['children'].push(node);
            } else {
                // If parent does not exist as node, create it at the root level, 
                // and add it to first level elements array.
                graph.push(mapped[parentid] = {
                    id: parentid,
                    parentids: [],
                    children: [node]
                });
            }
        });
    });
    return graph;
}
// Sample data
var arr = [{
   'id': 9,
   'parentid': 7
}, {
   'id': 9,
   'parentid': 8
}, {
   'id': 10,
   'parentid': 9
}];
// Convert:
var graph = unflatten(arr);
console.log(JSON.stringify(graph, null, 4));
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
&#13;
&#13;