代码之家  ›  专栏  ›  技术社区  ›  MyDaftQuestions

如何将数组转换为层次数组

  •  5
  • MyDaftQuestions  · 技术社区  · 8 年前

    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 也不会总是从根源开始

    5 回复  |  直到 8 年前
        1
  •  2
  •   ibrahim mahrir    8 年前

    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: [] } 减少 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 位,它再次在数组上循环,现在它为每个对象获取其对象 .child 从…起 物件 .ticket children (对其的引用存储在 儿童 对象中的对象 物件 .

        2
  •  1
  •   baao    8 年前

    let 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'}
    ];
    
    let children = currentData.map(e => e.child);
    currentData.sort((a,b) => children.indexOf(a.ticket));
    
    let res = currentData.reduce((a,b) => {
        if (! children.includes(b.ticket)) {
            return a.set(b.ticket, (a.get(b.ticket) || [])
                .concat({ticket: b.child,
                    children: currentData
                        .filter(el => el.ticket === b.child)
                        .map(el => ({ticket: el.child, children: []}))}))
        }
        return a;
    }, new Map);
    
    let r = {};
    
    for (let [key,value] of res.entries()) {
        r.ticket = key;
        r.children = value;
    }
    
    console.log(r);
        3
  •  1
  •   Vanojx1    8 年前

    使用递归解决方案,可以更改起始节点。

    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'}];
    
    function convert(data, start){
      return {
        ticket: start,
        childs: data.filter(d => d.ticket == start)
                    .reduce((curr, next) => curr.concat([next.child]), [])
                    .map(c => convert(data, c))
      }
    }
    
    let result = convert(currentData, 'cap');
    
    console.log(result);
    .as-console-wrapper{top: 0; max-height: none!important;}
        4
  •  1
  •   Piyin    8 年前

    for 方法如下:

    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 leafs = {};
    var roots = {};
    var tickets = {};
    for(var i=0; i<currentData.length; i++){
        var ticket = currentData[i].ticket;
        var child = currentData[i].child;
        if(!tickets[ticket]){
            tickets[ticket] = {ticket:ticket,children:[]};
            if(!leafs[ticket]){
                roots[ticket] = true;
            }
        }
        if(!tickets[child]){
            tickets[child] = {ticket:child,children:[]};
        }
        delete roots[child];
        leafs[child] = true;
        tickets[ticket].children.push(tickets[child]);
    }
    for(var ticket in roots){
        console.log(tickets[ticket]);
    }
        5
  •  0
  •   Koushik Chatterjee    8 年前

    如果你不熟悉 reduce map , forEach

    var currentData = [
        {'ticket':'CT-1', 'child':'CT-1-A'},
        {'ticket':'CT-1', 'child':'CT-1-B'},
        {'ticket':'CAP', 'child':'CT-1'},
        {'ticket':'CAP', 'child':'CT-2'}
    ];
    function buildHierarchy(flatArr) {
        let root = {},
            nonRoot = {},
            tempMap = {};
        Object.setPrototypeOf(root, nonRoot);
        for (let idx = 0; idx < flatArr.length; idx++) {
            let currTicket = flatArr[idx];
            let tempTicket = tempMap[currTicket.ticket] || {ticket: currTicket.ticket, children: []};
            tempMap[currTicket.ticket] = tempTicket;
            if (currTicket.child) {
                let tempChild = tempMap[currTicket.child] || {ticket: currTicket.child, children: []};
                tempTicket.children.push(tempChild);
                tempMap[currTicket.child] = tempChild;
                delete root[tempChild.ticket];
                nonRoot[tempChild.ticket] = true;
            }
            root[tempTicket.ticket] = true;
    
        }
        return tempMap[Object.keys(root)[0]];
    }
    
    console.log(buildHierarchy(currentData));

    我已经更改了源数组的顺序,以便将根对象放在任何位置,代码应该可以处理这个问题。