在javascript中将数组转换为嵌套对象

时间:2016-01-08 14:40:25

标签: javascript arrays node.js tree

我有典型的组织hierarchy。例如。

D,E is reporting to B. B,C is reporting to A.

A是最顶级的节点。但是我将这些数据作为一个平面数组接收,其属性指向父级。

    [{
      name: "A",
      parent: null
    },
    {
      name: "B",
      parent: "A"
    },
    {
      name: "C",
      parent: "A"
    },
    {
      name: "D",
      parent: "B"
    },
    {
      name: "E",
      parent: "B"
    }]

但我希望将其转换为single nested objecttree。根节点具有子属性,其中嵌入了子节点,并且每个子节点都有自己的子属性,如下所示。

    {
      name: "A",
      children: [{
        name: "C"
        children: [{
          name: "D"
        },{
          name: "E"
        }]
      },{
        name: "C"
      }]
    }

如何有效地在javascript中执行此操作?

3 个答案:

答案 0 :(得分:5)

与其他解决方案不同,它使用单个循环 - 数据的顺序并不重要 - 示例与问题的顺序不同

var peeps = [
    { name: "D", parent: "B" }, 
    { name: "B", parent: "A" },
    { name: "A", parent: null }, 
    { name: "C", parent: "A" }, 
    { name: "E", parent: "B" }
];

var tree;
var obj = {};
peeps.forEach(function (peep) {
    var name = peep.name,
        parent = peep.parent,
        a = obj[name] || { name: name };
    if (parent) {
        obj[parent] = obj[parent] || { name: parent };
        obj[parent].children = obj[parent].children || [];
        obj[parent].children.push(a);
    } else {
        tree = obj[name];
    }
    obj[name] = obj[name] || a;
});
console.log(tree);

答案 1 :(得分:3)

此解决方案为Jaromanda X'solution添加了一些内容。

  1. Array.prototype.reduce代替Array.prototype.forEach,因为需要临时变量和返回值。

  2. 保留r[a.name].children的内容并将其分配给a.children

  3. 节点a已分配给r[a.name]。因此,节点对象的所有属性都保留,例如prop1 ... prop5

  4. 根节点已分配给r._以供日后使用。

  5. var data = [
            { name: "D", parent: "B", prop1: 'prop1' },
            { name: "B", parent: "A", prop2: 'prop2' },
            { name: "A", parent: null, prop3: 'prop3' },
            { name: "C", parent: "A", prop4: 'prop4' },
            { name: "E", parent: "B", prop5: 'prop5' }
        ],
        tree = data.reduce(function (r, a) {
            a.children = r[a.name] && r[a.name].children;
            r[a.name] = a;
            if (a.parent) {
                r[a.parent] = r[a.parent] || {};
                r[a.parent].children = r[a.parent].children || [];
                r[a.parent].children.push(a);
            } else {
                r._ = a;
            }
            return r;
        }, {})._;
    document.write('<pre>' + JSON.stringify(tree, 0, 4) + '</pre>');

    对于多个根,您可以使用root的父级作为子级的访问者并返回此数组

    var data = [{ name: "D", parent: "B", prop1: 'prop1' }, { name: "B", parent: "A", prop2: 'prop2' }, { name: "A", parent: null, prop3: 'prop3' }, { name: "C", parent: "A", prop4: 'prop4' }, { name: "E", parent: "B", prop5: 'prop5' }, { name: "A1", parent: null, prop3: 'prop3' }],
        tree = data.reduce(function (r, a) {
            if (r[a.name] && r[a.name].children) { // prevent empty children array
                a.children = r[a.name].children;
            }
            r[a.name] = a;
            r[a.parent] = r[a.parent] || {};
            r[a.parent].children = r[a.parent].children || [];
            r[a.parent].children.push(a);
            return r;
        }, {}).null.children; // take root value as property accessor
    
    console.log(tree);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:2)

您可以使用while循环执行此操作:

var data = [
    { name: "A", parent: null },
    { name: "B", parent: "A" },
    { name: "C", parent: "A" },
    { name: "D", parent: "B" },
    { name: "E", parent: "B" }
];

var root = data.find(function(item) {
    return item.parent === null;
});

var tree = {
    name: root.name
};

var parents = [tree];
while (parents.length > 0) {
    var newParents = [];
    parents.forEach(function(parent) {
        var childs = data.filter(function(item) {
            return item.parent == parent.name
        }).forEach(function(child) {
            var c = { name: child.name };
            parent.children = parent.children || [];
            parent.children.push(c);
            newParents.push(c);
        });
    });
    parents = newParents;
}

console.log(tree);