【问题标题】:JavaScript format array of objects into nested childrenJavaScript 将对象数组格式化为嵌套的子对象
【发布时间】:2016-04-15 17:56:07
【问题描述】:

我有一个包含 parentId 和排序值的对象数组,我想将它们放入包含嵌套“子项”的数组中并进行适当排序。

例如,这是数据:

[{
    id: 1,
    sort: 2,
    parentId: null,
    name: 'A'
}, {
    id: 2,
    sort: 1,
    parentId: 1,
    name: 'A.1'
}, {
    id: 3
    sort: 2,
    parentId: 1,
    name: 'A.2'
}, {
    id: 4,
    sort: 1,
    parentId: null,
    name: 'B'
}]

我想改变它的方式是:

[{
    id: 4,
    sort: 1,
    parentId: null,
    name: 'B',
    children: []
}, {
    id: 1,
    sort: 2,
    parentId: null,
    name: 'A',
    children: [{
        id: 2,
        sort: 1,
        parentId: 1,
        name: 'A.1'
    }, {
        id: 3
        sort: 2,
        parentId: 1,
        name: 'A.2'
    }]
}]

这是已排序的(id 4 位于顶部,因为 sort 为 1)并且子级嵌套并相应地排序。

有什么好的方法可以做到这一点吗?我可以递归循环以应用孩子,但不确定如何保持排序。

【问题讨论】:

  • names 只有一个字符吗? name 的第一部分是像 A-Z 那样只有字母还是有数字和特殊字符?
  • @stackErr 我认为名字在这里根本不重要,你不需要他们来回答这个问题。他添加了这些内容,以便我们更轻松地查看所有内容的去向。
  • @stackErr 是的,这些名称只是为了简单起见。所有逻辑都将基于 id、parentId 和排序。
  • 有无尽的关卡吗?还是只有两个深?
  • 只有两个,但可能它应该通过递归支持任何级别

标签: javascript arrays sorting


【解决方案1】:

这是一个先排序后过滤的提案。

排序采用属性parentIdsort。这对于下一步是必要的,因为“过滤”需要一个排序的数组。

稍后数组使用Array#filter() 过滤,这里是thisArgs 用于引用节点以插入可能的子节点。

编辑:更新未排序的 (id/parentId) 数据。

var array = [{ id: 1, sort: 2, parentId: null, name: 'A' }, { id: 2, sort: 1, parentId: 1, name: 'A.1' }, { id: 3, sort: 2, parentId: 1, name: 'A.2' }, { id: 4, sort: 1, parentId: null, name: 'B' }],
    nested;

array.sort(function (a, b) {
    return (a.parentId || -1) - (b.parentId || -1) || a.sort - b.sort;
});

nested = array.filter(function (a) {
    a.children = this[a.id] && this[a.id].children;
    this[a.id] = a;
    if (a.parentId === null) {
        return true;
    }
    this[a.parentId] = this[a.parentId] || {};
    this[a.parentId].children = this[a.parentId].children || [];
    this[a.parentId].children.push(a);
}, Object.create(null));

document.write('<pre>' + JSON.stringify(nested, 0, 4) + '</pre>');

【讨论】:

  • 这并不总是有效,因为它使用parentId 对数据进行排序,这无关紧要。试试看:[{id: 1, parentId: null, sort: 1}, {id: 2, parentId: 3, sort: 1}, {id: 3, parentId: 2, sort: 1}],你会发现自己有一个例外。除此之外,thisArgfilter 的把戏真的很棒。
  • 您的数据无效。它有一个循环引用。 2 -> 3, 3 -> 2
  • @NinaScholz 是的,抱歉,这是一个更好的例子:[{id: 1, parentId: 4, sort: 1}, {id: 2, parentId: 3, sort: 1}, {id: 3, parentId: 1, sort: 1}, {id: 4, parentId: null, sort: 1}]
  • @VonD,请参阅编辑,它现在应该适用于(某种)未排序的数据。
【解决方案2】:

我试了一下又回来了,已经有其他答案了,不过还是贴出来吧。

这个方法修改了原来的Array:

var items = [{id: 1,sort: 2,parentId: null,name: 'A'}, {id: 2,sort: 1,parentId: 1,name: 'A.1'}, {id: 3,sort: 2,parentId: 1,name: 'A.2'}, {id: 4,sort: 1,parentId: null,name: 'B'}];


function generate_tree(arr){
  var references = {};
  arr.sort(function(a,b){
    // Save references to each item by id while sorting
    references[a.id] = a; references[b.id] = b;
    // Add a children property
    a.children = []; b.children = [];
    if(a.sort > b.sort) return 1;
    if(a.sort < b.sort) return -1;
    return 0;
  });

  for(var i=0; i<arr.length; i++){
    var item = arr[i];
    if(item.parentId !== null && references.hasOwnProperty(item.parentId)){
      references[item.parentId].children.push(arr.splice(i,1)[0]);
      i--; // Because the current index now contains the next item
    }
  }
  return arr;
}

document.body.innerHTML = "<pre>" + JSON.stringify(generate_tree(items), null, 4) + "</pre>";

【讨论】:

    【解决方案3】:
    1. 我会创建一个新的数据结构,如下所示:

      { 1: { 编号:1, 排序:2, 父ID:空, 名称:'A' }, 2:{ 编号:4, 排序:1, 父ID:空, 名称:'B' } }

    注意事项:新结构是一个对象,而不是数组,它只包含其中最顶层的元素(带有parentId null 的元素)

    1. 然后,对原始数组执行for,并分配new_obj[ orig_arr_curr_elem[parentId] ].children.push(orig_arr_curr_elem)

    2. 然后使用new_obj sort()(或children 属性)中的元素创建一个新数组

    实现步骤 1 和 2 的代码(使用节点运行):

    var util = require('util');
    var old_arr = [{
        id: 1,
        sort: 2,
        parentId: null,
        name: 'A'
    }, {
        id: 2,
        sort: 1,
        parentId: 1,
        name: 'A.1'
    }, {
        id: 3,
        sort: 2,
        parentId: 1,
        name: 'A.2'
    }, {
        id: 4,
        sort: 1,
        parentId: null,
        name: 'B'
    }];
    
    var new_obj = {};
    for (var i = 0; i < old_arr.length; i++){
        if ( old_arr[i].parentId == null )
            new_obj[ old_arr[i].id ] = old_arr[i];
    }
    
    for (var i = 0; i < old_arr.length; i++){
        if ( old_arr[i].parentId == null ) continue;
        new_obj[ old_arr[i].parentId ].children = new_obj[ old_arr[i].parentId ].children || [];
        new_obj[ old_arr[i].parentId ].children.push( old_arr[i] );
    }
    
    console.log(util.inspect(new_obj, {showHidden: false, depth: null}));
    

    【讨论】:

      猜你喜欢
      • 2020-06-21
      • 2018-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 2023-04-08
      相关资源
      最近更新 更多