javascript - 如何将数组转换为分层数组

标签 javascript arrays

我有一些数据是

var currentData = [
    {'ticket':'CAP', 'child':'CT-1'},
    {'ticket':'CAP', 'child':'CT-2'},
    {'ticket':'CT-1', 'child':'CT-1-A'},
    {'ticket':'CT-1', 'child':'CT-1-B'}
];

数据是扁平的,我需要将它转换成类似的东西:

{
    'ticket': 'CAP',
    children : [{
        'ticket' : 'CT-1',
        'children' : [{
            'ticket' : 'CT-1-A',
            'children' : []
        }, {
            'ticket' : 'CT-1-B',
            'children' : []
        }],
        [{
            'ticket' : 'CT-2',
            'children' : []
        }]
    }]
}

(我认为以上是有效的)?

我不知道怎么做。我将展示我的努力,但我不确定我的方法是否正确。

var currentData = [{'ticket':'cap', 'child':'CT-1'},{'ticket':'cap', 'child':'CT-2'}, {'ticket':'CT-1', 'child':'CT-1-A'},{'ticket':'CT-1', 'child':'CT-1-B'}];

var newList = [];
function convert(list){
    if (newList.length <= 0){
        var child = [];
        var emptyChild = [];
        child.push({'ticket': list[0].child, 'child': emptyChild });
        newList.push({'ticket': list[0].ticket, 'children' : child});
        list.splice(0,1);
    } // the if statement above works fine
    
    for(var i = 0;  i < list.length; i++) {
        var ticket = list[i].ticket;
        for(var j = 0; j < newList.length; j++) {
            if (newList[j].ticket == ticket){
                var child;
                var emptyChild = [];
                child = {'ticket': list[i].child, 'child': emptyChild };
                newList[j].children.push(child);
                list.splice(i,1);
                break;
            } // the if above works
            else{
                var child2 = getFromChildren(ticket, newList, list[i]); // child2 is Always null, even if getFromChildren returns an object
                newList[j].children.push(child2);
                list.splice(i,1);
                break;
            }
        }
    }   
    
    if (list.length > 0){
        convert(list);
    }
}

function getFromChildren(ticket, list, itemToAdd){

    if (list == null || list[0].children == null)
        return;
    
    for(var i = 0; i < list.length; i++) {
        if (list[i] == null)
        return;
        
        if (list[i].ticket == ticket){
            list[i].child.push(itemToAdd.child); // ** can't do this, javascript passes by value, not by reference :(
        } else{
            getFromChildren(ticket, list[i].children, itemToAdd);
        }
    }
}

convert(currentData);

我想我把它弄得一团糟。在评论中我放了一个 ** 解释说它不工作是因为 JavaScript 没有通过引用传递,但是在 further reading 上。我认为这是不正确的,因为我正在传递通过引用传递的对象?

编辑

遗憾的是,currentData 显示的数据并不总是从根开始

最佳答案

function convert(arr) {
  var children = {};                                         // this object will hold a reference to all children arrays

  var res = arr.reduce(function(res, o) {                    // for each object o in the array arr
    if(!res[o.ticket]) {                                     // if there is no object for the element o.ticket
      res[o.ticket] = {ticket: o.ticket, children: []};      // then creates an object for it
      children[o.ticket] = res[o.ticket].children;           // and store a reference to its children array
    }
    if(!res[o.child]) {                                      // if there is no object for the element o.child
      res[o.child] = {ticket: o.child, children: []};        // then creates an object for it
      children[o.child] = res[o.child].children;             // and store a reference to its children array
    }
    return res;
  }, {});
  
  arr.forEach(function(o) {                                  // now for each object o in the array arr
    children[o.ticket].push(res[o.child]);                   // add the object of o.child (from res) to its children array
    delete res[o.child];                                     // and remove the child object from the object res
  });
  
  return res;
}



var currentData = [
    {'ticket':'CAP', 'child':'CT-1'},
    {'ticket':'CAP', 'child':'CT-2'},
    {'ticket':'CT-1', 'child':'CT-1-A'},
    {'ticket':'CT-1', 'child':'CT-1-B'}
];

console.log(convert(currentData));

解释:

reduce 部分为每个元素(子元素或非子元素)创建一个形式为:{ ticket: "...", children: [] } 的对象。所以在 reduce 之后,对象 res 将是:

res = {
    'CAP': { ticket: 'CAP', children: [] },
    'CT-1': { ticket: 'CT-1', children: [] },
    'CT-2': { ticket: 'CT-2', children: [] },
    'CT-1-A': { ticket: 'CT-1-A', children: [] },
    'CT-1-B': { ticket: 'CT-1-B', children: [] },
}

现在是 forEach 位,它再次遍历数组,现在对于每个对象,它从 res 中获取 .child 的对象> 在上面,将它插入 .ticket 对象的 children(对它的引用存储在 children 对象中),然后删除 .child 对象来自对象 res

关于javascript - 如何将数组转换为分层数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46241210/

相关文章:

javascript - 如何读取txt文件并将其保存在html中的javascript数组中

javascript - 将数据推送到两级数组上

java - 在 main 中创建数组并用来自单独线程的数据填充它

javascript - 带有流类型注释的混合

javascript - Drupal 中的谷歌地图 : reference to gmap object from JavaScript

javascript - Netbeans javascript 评论

arrays - 数组索引超出范围

javascript - 将 SPA 中的 client_id 和 client_secret 发送到 auth 服务器有什么意义?

javascript - 添加动态行无法获取对创建的选择输入的引用

c++ - 无法将文本文件中的数据读入数组