JavaScript format array of objects into nested children

筅森魡賤 提交于 2021-02-04 18:52:08

问题


I have an array of objects with parentId and sort values that I'd like to put into an array with nested 'children' and sorted appropriately.

For example, here's the data:

[{
    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'
}]

The way I'd like to transform this would be such as:

[{
    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'
    }]
}]

This is sorted (id 4 being at the top, since sort is 1) and the children are nested and also sorted accordingly.

Any suggestions on a good way to do this? I can recursively loop through to apply children, but not sure how I can maintain sorting on this.


回答1:


This is a proposal which sorts first and filters after that.

The sorting takes the properties parentId and sort. This is necessary for the next step, because the "filtering" needs a sorted array.

Later the array is filterd with Array#filter(), Here is thisArgs used for referencing nodes for a possible insertation of children.

Edit: Update for unsorted (id/parentId) data.

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>');



回答2:


I gave it a try and came back, and there are already other answers, but I'm posting it anyway.

This method modifies the original 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. I'd create a new data structure, to look like:

    { 1: { id: 1, sort: 2, parentId: null, name: 'A' }, 2: { id: 4, sort: 1, parentId: null, name: 'B' } }

Things to notice: the new structure is an object, not an array, that contains only the topmost elements in it (the ones with parentId null)

  1. Then, do a for over the original array, and assign new_obj[ orig_arr_curr_elem[parentId] ].children.push(orig_arr_curr_elem)

  2. Then create a new array with the elems from new_obj sort() the (or the children property) however you want

Code that implements the steps 1 and 2 (run this using node):

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}));


来源:https://stackoverflow.com/questions/36605002/javascript-format-array-of-objects-into-nested-children

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!