从对象树构造平面数组

时间:2015-09-16 12:58:14

标签: javascript arrays algorithm tree hierarchy

假设我有一个如下所示的对象树,可能是使用此处的优秀算法创建的:https://stackoverflow.com/a/22367819/3123195

{
    "children": [{
        "id": 1,
        "title": "home",
        "parent": null,
        "children": []
    }, {
        "id": 2,
        "title": "about",
        "parent": null,
        "children": [{
            "id": 3,
            "title": "team",
            "parent": 2,
            "children": []
        }, {
            "id": 4,
            "title": "company",
            "parent": 2,
            "children": []
        }]
    }]
}

(特别是在此示例中,该函数返回的数组嵌套在另一个空对象中的children数组属性中。)

如何将其转换回平面阵列?

6 个答案:

答案 0 :(得分:3)

此功能可以完成这项工作,并为每个对象添加一个关卡指示器。 treeObj的直接子项为1级,子级为2级等。parent属性也会更新。

function flatten(treeObj, idAttr, parentAttr, childrenAttr, levelAttr) {
    if (!idAttr) idAttr = 'id';
    if (!parentAttr) parentAttr = 'parent';
    if (!childrenAttr) childrenAttr = 'children';
    if (!levelAttr) levelAttr = 'level';

    function flattenChild(childObj, parentId, level) {
        var array = []; 

        var childCopy = angular.extend({}, childObj);
        childCopy[levelAttr] = level;
        childCopy[parentAttr] = parentId;
        delete childCopy[childrenAttr];
        array.push(childCopy);

        array = array.concat(processChildren(childObj, level));

        return array;
    };

    function processChildren(obj, level) {
        if (!level) level = 0;
        var array = [];

        obj[childrenAttr].forEach(function(childObj) {
            array = array.concat(flattenChild(childObj, obj[idAttr], level+1));
        });

        return array;
    };

    var result = processChildren(treeObj);
    return result;
};

此解决方案利用Angular的angular.extend()函数来执行子对象的副本。将其与任何其他库的等效方法或本机函数联系起来应该是一个微不足道的变化。

上面例子给出的输出是:

[{
    "id": 1,
    "title": "home",
    "parent": null,
    "level": 1
}, {
    "id": 2,
    "title": "about",
    "parent": null,
    "level": 1
}, {
    "id": 3,
    "title": "team",
    "parent": 2,
    "level": 2
}, {
    "id": 4,
    "title": "company",
    "parent": 2,
    "level": 2
}]

值得注意的是,此函数不保证数组将按id排序;它将基于操作期间遇到各个对象的顺序。

Fiddle!

答案 1 :(得分:2)

这是我的贡献:

function flatNestedList(nestedList, childrenName, parentPropertyName, idName, newFlatList, parentId) {

        if (newFlatList.length === 0)
            newFlatList = [];

        $.each(nestedList, function (i, item) {
            item[parentPropertyName] = parentId;
            newFlatList.push(item);
            if (item[childrenName] && item[childrenName].length > 0) {
                //each level
                flatNestedList(item[childrenName], childrenName, parentPropertyName, idName, newFlatList, item[idName]);
            }
        });

        for (var i in newFlatList)
            delete (newFlatList[i][childrenName]);
    }

答案 2 :(得分:2)

希望你熟悉es6:

let flatten = (children, extractChildren) => Array.prototype.concat.apply(
  children, 
  children.map(x => flatten(extractChildren(x) || [], extractChildren))
);

let extractChildren = x => x.children;

let flat = flatten(extractChildren(treeStructure), extractChildren)
               .map(x => delete x.children && x);

<强> UPD:

抱歉,您没有注意到您需要设置父级和级别。请在下面找到新功能:

let flatten = (children, getChildren, level, parent) => Array.prototype.concat.apply(
  children.map(x => ({ ...x, level: level || 1, parent: parent || null })), 
  children.map(x => flatten(getChildren(x) || [], getChildren, (level || 1) + 1, x.id))
);

https://jsbin.com/socono/edit?js,console

答案 3 :(得分:0)

尝试以下操作仅假设每个项目都具有子级属性

class TreeStructureHelper {
   public toArray(nodes: any[], arr: any[]) {
    if (!nodes) {
      return [];
    }
    if (!arr) {
      arr = [];
    }
    for (var i = 0; i < nodes.length; i++) {
      arr.push(nodes[i]);
      this.toArray(nodes[i].children, arr);
    }
  return arr;
 }
}

用法

 let treeNode =
 {
   children: [{
    id: 1,
    title: "home",
    parent: null,
    children: []
   }, {
    id: 2,
    title: "about",
    parent: null,
    children: [{
        id: 3,
        title: "team",
        parent: 2,
        children: []
     }, {
        id: 4,
        title: "company",
        parent: 2,
        children: []
     }]
   }]
 };
 let flattenArray = _treeStructureHelper.toArray([treeNode], []);

答案 4 :(得分:0)

这是数据:

 const data = {
      id: '1',
      children: [
        {
          id: '2',
          children: [
            {
              id: '4',
              children: [
                {
                  id: '5'
                },
                {
                  id: '6'
                }
              ]
            },
            {
              id: '7'
            }
          ]
        },
        {
          id: '3',
          children: [
            {
              id: '8'
            },
            {
              id: '9'
            }
          ]
        }
      ]
    }

在React.JS中,只需在状态中声明一个数组字段并将项目推送到该数组即可。

  const getAllItemsPerChildren = item => {
    array.push(item);
    if (item.children) {
      return item.children.map(i => getAllItemsPerChildren(i));
    }
  }

在函数调用后,处于状态的数组将保留所有项目,如下所示:

enter image description here

答案 5 :(得分:0)

再来一张??

function flatten(root, parent=null, depth=0, key='id', flat=[], pick=() => {}) {
    flat.push({
        parent,
        [key]: root[key],
        depth: depth++,
        ...pick(root, parent, depth, key, flat)
    });
    
    if(Array.isArray(root.children)) {
        root.children.forEach(child => flatten(child, root[key], depth, key, flat, pick));
    }
}

let sample = {
    "id": 0,
    "children": [{
        "id": 1,
        "title": "home",
        "parent": null,
        "children": []
    }, {
        "id": 2,
        "title": "about",
        "parent": null,
        "children": [{
            "id": 3,
            "title": "team",
            "parent": 2,
            "children": []
        }, {
            "id": 4,
            "title": "company",
            "parent": 2,
            "children": []
        }]
    }]
};

let flat = [];

flatten(sample, null, 0, 'id', flat, root => ({ title: root.title }));

let expected = [
    {
        "id": 0,
        "parent": null,
        "depth": 0
    },
    {
        "id": 1,
        "parent": 0,
        "depth": 1,
        "title": "home"
    },
    {
        "id": 2,
        "parent": 0,
        "depth": 1,
        "title": "about"
    },
    {
        "id": 3,
        "parent": 2,
        "depth": 2,
        "title": "team"
    },
    {
        "id": 4,
        "parent": 2,
        "depth": 2,
        "title": "company"
    }
];