将平面结构转换为层次结构

Converting flat structure to hierarchical

我需要创建能够将平面对象转换为递归对象的函数。这是我的例子: 我有平面阵列:

var flatArray = [
    {
        Description: "G",
        guid: "c8e63b35",
        parent: null,
    },
    {
        Description: "Z",
        guid: "b1113b35",
        parent: "c8e63b35",
    },
    {
        Description: "F",
        guid: "d2cc2233",
        parent: "b1113b35",
    },
    {
        Description: "L",
        guid: "a24a3b1a",
        parent: null,
    },
    {
        Description: "K",
        guid: "cd3b11caa",
        parent: "a24a3b1a",
    },      
]

结果应该是:

recursiveArray = [
    {
        Description: "G",
        guid: "c8e63b35",
        parent: null,
        Children: [
            {
                Description: "Z",
                guid: "b1113b35",
                parent: "c8e63b35",
                Children: [
                    {
                        Description: "F",
                        guid: "d2cc2233",
                        parent: "b1113b35",
                    }
                ]
            }, 
        ]
    },
    {
        Description: "L",
        guid: "a24a3b1a",
        parent: null,
        Children: [
        {
            Description: "K",
            guid: "cd3b11caa",
            parent: "a24a3b1a",
        }
    }
]

请帮我想办法。一个可行的算法将不胜感激,因为我对如何正确执行此操作有疑问。在每种情况下,我都需要在递归结构中找到已检查元素的特定位置,并将其推入已找到的元素子数组中。我认为这是愚蠢和低效的。有什么方法可以快速有效地做到这一点吗?

编辑:递归数组格式错误。现在应该可以了。 我的数组没有以任何方式排序。

我尝试用伪代码编写算法,最后得到的 JS 代码几乎可以工作(可能需要一些额外的 validations/checks),但展示了解决问题的一般方法。

//Lets separate children (nodes with a parent) from roots (nodes without a parent)
var children = flatArray.filter(function(object){
    return object.parent !== null;
});

var roots = flatArray.filter(function(object){
    return object.parent === null;
});

//And add each child to the nodes tree
children.foreach(function(child){
    recursiveAdd(roots, child);
});

//To add a children node, node tree is searched recursively for a parent
function recursiveAdd(nodes, child){
    nodes.foreach(function(parent){
        if(parent.guid === child.parent){
            parent.Children = parent.Children | [];
            parent.Children.add(child);
        } else if(parent.Children) {
            recursiveAdd(parent.Children, child);
        }
    });
}

//Temporary children array can be garbage collected
children = null;
//Resulting node tree
var recursiveArray = roots;

这个递归函数对你有好处:

var flatArray = [{
  Description: "G",
  guid: "c8e63b35",
  parent: null,
  Children: []
}, {
  Description: "Z",
  guid: "b1113b35",
  parent: "c8e63b35",
  Children: []
}, {
  Description: "F",
  guid: "d2cc2233",
  parent: "b1113b35",
  Children: []
}, {
  Description: "L",
  guid: "a24a3b1a",
  parent: null,
  Children: []
}, {
  Description: "K",
  guid: "cd3b11caa",
  parent: "a24a3b1a",
  Children: []
}, ];




for (var i = 0; i < flatArray.length; i++) {
  recursive(flatArray[i]);
}


function recursive(a) {
  for (var i = 0; i < flatArray.length; i++) {
    if (flatArray[i].parent == a.guid) {
      var b = flatArray[i];
      recursive(b);
      a.Children.push(b);
    }
  }
}


console.log(flatArray)

我会这样做:

var flatArray = [{
    Description: "G",
    guid: "c8e63b35",
    parent: null,
}, {
    Description: "Z",
    guid: "b1113b35",
    parent: "c8e63b35",
}, {
    Description: "F",
    guid: "d2cc2233",
    parent: "b1113b35",
}, {
    Description: "L",
    guid: "a24a3b1a",
    parent: null,
}, {
    Description: "K",
    guid: "cd3b11caa",
    parent: "a24a3b1a",
}];

var recursiveArray = unflatten(flatArray);

alert(JSON.stringify(recursiveArray, null, 4));
<script>
function unflatten(items) {
    return items.reduce(insert, {
        res: [],
        map: {}
    }).res;
}

function insert(obj, item) {
    var parent     = item.parent;
    var map        = obj.map;
    map[item.guid] = item;

    if (parent === null) obj.res.push(item);
    else {
        var parentItem = map[parent];

        if (parentItem.hasOwnProperty("Children"))
            parentItem.Children.push(item);
        else parentItem.Children = [item];
    }

    return obj;
}
</script>

当然,这只有在您的 flatArray 具有每个父项出现在其子项之前的 属性 时才有效。

希望对您有所帮助。

var flatArray = [
    {
        Description: "G",
        guid: "c8e63b35",
        parent: null,
    },
    {
        Description: "Z",
        guid: "b1113b35",
        parent: "c8e63b35",
    },
    {
        Description: "F",
        guid: "d2cc2233",
        parent: "b1113b35",
    },
    {
        Description: "L",
        guid: "a24a3b1a",
        parent: null,
    },
    {
        Description: "K",
        guid: "cd3b11caa",
        parent: "a24a3b1a",
    },      
];

//for printing
function htmlPrint(obj) {
  document.write('<pre>'+JSON.stringify(obj,null,2)+'</pre>');
};

var guids = {};
var roots = [];

flatArray.forEach(function(node){ 
  guids[node.guid] = node;       //save into a hash
  node.Children = [];            //make sure it has a children array
  //save it as root if it is a root
  if(node.parent === null){ roots.push(node);}
});
flatArray.forEach(function(node){ 
  //if it has a parent, add self to parent's children
  var parent = guids[node.parent]; 
  if(parent)  parent.Children.push(node); 
});
htmlPrint(roots);

这个很好用并且易于阅读:

function flatToHierarchy (flat) {

    var roots = [] // things without parent

    // make them accessible by guid on this map
    var all = {}

    flat.forEach(function(item) {
      all[item.guid] = item
    })

    // connect childrens to its parent, and split roots apart
    Object.keys(all).forEach(function (guid) {
        var item = all[guid]
        if (item.parent === null) {
            roots.push(item)
        } else if (item.parent in all) {
            var p = all[item.parent]
            if (!('Children' in p)) {
                p.Children = []
            }
            p.Children.push(item)
        }
    })

    // done!
    return roots
}

您可以在 Angular.

中使用以下代码
flatToHierarchy(flat: any[], parent: any = null, Key: string = 'id', parentKey: string = 'parentId') {
  var leafs: any = [];

  if (!parent) {
    leafs = flat.filter((x: { [x: string]: any; }) => x[parentKey] === null);
  } else {
    leafs = flat.filter((x: { [x: string]: any; }) => x[parentKey] === parent[Key]);
  }

  if (!leafs || leafs.length == 0) {
    return;
  } else {
      leafs.forEach((item: { children: any[]; }) => {
      item.children = [];
      item.children = this.flatToHierarchy(flat, item);
    });
  }
  return leafs;
}

像这样使用

 this.flatToHierarchy(flatItems);