【问题标题】:Array with children - display it in the form of parent-child hierarchyArray with children - 以父子层次的形式显示
【发布时间】:2015-10-20 18:01:37
【问题描述】:

我有步骤#1中显示的数据,我想根据“id”以父级的形式重新排列它,如步骤#2中的相应子级:

step#1:                                                                                             
[
    {"id": "card:1.usa", "name": "usa"}, {"id": "card:2", "name": "card2"}, {"id": "card:1", "name": "card1"}, {"id": "card:2.washington", "name": "washington"},
    {"id": "card:1.usa.illinios", "name": "illinios"}, {"id": "card:1.usa.illinios.city1", "name": "chicago"}
]

step#2 :   
[
    {"id": "card:1", "name": "card1", "children": [ {"id": "card:1.usa", "name": "usa", "children":[ {"id": "card:1.usa.illinios", "name": "illinios", "children":[ {"id": "card:1.usa.illinios.city1", "name": "chicago"}] }] }    },
    {"id": "card:2", "name": "card2", "children": [ {"id": "card:2.washington", "name": "washington" }] }
]

我尝试从我身边做以下事情,但这只会得到第一级孩子:

var cardData = [
    {"id": "card:1.usa", "name": "usa"}, {"id": "card:2", "name": "card2"}, {"id": "card:1", "name": "card1"}, {"id": "card:2.washington", "name": "washington"},
    {"id": "card:1.usa.illinios", "name": "illinios"}, {"id": "card:1.usa.illinios.city1", "name": "chicago"}
]
var subCardList = [];
$scope.parentCard = [];
for(var i=0; i<cardData.length; i++){
    if( cardData[i].id.indexOf('.') > -1){
        subCardList.push( cardData[i] );
    }
}
for(var i=0; i<cardData.length; i++){
    for(var j=0; j<subCardList.length; j++){
        var cardObj = {};
        if( cardData[i].id == subCardList[j].id.substr(0, subCardList[j].id.indexOf('.')) ){ //found matching parent card
            cardObj.id = cardData[i].id;
            cardObj.children = subCardList[j];
            $scope.parentCard.push( cardObj );
        }
    }
}

请告诉我如何通过 javascript/jquery 实现这一点?

【问题讨论】:

  • 你应该只对你的 $scope 应用你认为必要的东西。
  • @gr3g - 移除 $scope 变量
  • @SAM 添加了一个修改后的解决方案来处理边缘情况

标签: javascript jquery angularjs tree


【解决方案1】:

我改进了我的解决方案,使其更全面,并处理层次结构中的所有卡片都不存在且顺序不同的情况。

处理前根据id对子卡数组进行排序。这样可以确保卡片的顺序不会破坏此代码。

首先收集所有顶级卡。然后将每个子卡放入桶中(儿童收藏)。

我提供了额外的数据集 (cardData1) 来突出边界条件。

如果您需要更多解释,请告诉我。

var cardData = [{
    "id": "card:1.usa",
    "name": "usa"
}, {
    "id": "card:2",
    "name": "card2"
}, {
    "id": "card:1",
    "name": "card1"
}, {
    "id": "card:2.washington",
    "name": "washington"
}, {
    "id": "card:1.usa.illinios",
    "name": "illinios"
}, {
    "id": "card:1.usa.illinios.city1",
    "name": "chicago"
}]

var cardData1 = [
    {
    "id": "card:1.usa.illinios.city1.municipality1",
    "name": "DumDum"
},{
    "id": "card:1.usa",
    "name": "usa"
}, {
    "id": "card:2",
    "name": "card2"
}, {
    "id": "card:1",
    "name": "card1"
}, {
    "id": "card:2.washington",
    "name": "washington"
},  {
    "id": "card:1.usa.illinios.city1",
    "name": "chicago"
},
               
               
               ]


var subCardList = [];
var subCardMap = {};
var parentCardList = [];
var cardMap = {};
for (var i = 0; i < cardData.length; i++) {
    if (cardData[i].id.indexOf('.') > -1) {
        subCardList.push(cardData[i]);
        subCardMap[cardData[i].id] = cardData[i];
    } else {
        //top level cards
        var cardId = cardData[i].id;
        var parentCard = {
            id: cardId,
            name: cardData[i].name,
            children: []
        };
        cardMap[cardId] = parentCard;
        parentCardList.push(parentCard);
    }
}
//Sort the subcard list to ensure missing hierarchial cards do not break implementation
subCardList.sort(function (a, b) {
    return a.id.toLowerCase().localeCompare(b.id.toLowerCase());
});

//Build buckets(children array) for child cards on the fly 
for (var j = 0; j < subCardList.length; j++) {
    var topCardId = subCardList[j].id.substr(0, subCardList[j].id.indexOf('.'));
    placeInBucket(topCardId, subCardList[j]); //find matching parent card from map
}

function placeInBucket(topCardId, childCard) {
    var topCard = cardMap[topCardId]; //get top card
    var childIds = childCard.id.split(".");
    childIds.splice(0, 1); //Remove the top card id
        
    var childId = "";
    var bucket = topCard.children; //Assign the initial bucket as the topcard children array
    //loop through all the hierarchy and create complete hierarchy
    for (var i = 0; i < childIds.length; i++) {
        var key = topCardId + childId + "." + childIds[i];
        if (!subCardMap[key]) {
            childId += "." + childIds[i];
            continue;
        } //Do not build hierarchy for missing subcards in the id chain
        var child = cardMap[key];
        if (!child) { 
            bucket.push(childCard);
          	cardMap[key] = childCard; //Register new child to cardMap
            break;
        }
        if (!child.children) child.children = []; //Add Children array to a leaf card if not existing
        bucket = child.children;
        childId += "." + childIds[i]; //Append the id to drill down the hierarchy
    }
}

console.log(JSON.stringify(parentCardList));

【讨论】:

  • 我想获得问题中步骤#2 中指定的最终数组结果。你给出的解决方案没有做到这一点:-(
  • @SAM 我明白了..我错过了嵌套。
  • 感谢您的解决方案。当它与 cmets 内联时更喜欢它!
  • @SAM:不客气。我要添加的另一项边界检查是是否没有父卡可以开始。一旦您发现子卡是孤儿,这是一个简单的检查。
【解决方案2】:

简短的回答:你需要一个recursive function,一个调用自身嵌套子元素的函数,直到你找到一个没有子元素的元素。

所以,首先,您要找到列表中的所有父母:

[
    {"id": "card:2", "name": "card2"}, 
    {"id": "card:1", "name": "card1"}, 
]

然后,对于这些对象中的每一个,您再次遍历数组,找到后代。例如,对于card:1:

[
    {"id": "card:1.usa", "name": "usa"},
    {"id": "card:1.usa.illinios", "name": "illinios"},
    {"id": "card:1.usa.illinios.city1", "name": "chicago"}
]

这是我们需要递归的地方:您需要再次重复相同的过程,将此数组作为您的输入。所以你会发现的“父母”是:

[
    {"id": "card:1.usa", "name": "usa"}
]

还有孩子们:

[
    {"id": "card:1.usa.illinios", "name": "illinios"},
    {"id": "card:1.usa.illinios.city1", "name": "chicago"}
]

因为你还有孩子,你会再重复一遍,直到你找不到更多的孩子。

这个例子可能不够干净(我不确定如何处理 id),但它确实有效:

function nestChildren(list, startIndex){
    var parents = [];

    // Search list for "parents" --> objects with only one period-separated section
    for(var i=0;i<list.length;i++){
        var ids = list[i].id.substring(startIndex).split('.'); // Count only sections from parent id

        if (ids.length == 1){
            parents.push(list[i]);
        } 
    }

    for(var i=0;i<parents.length;i++){
        var parent = parents[i];

        var children = [];

        // Search list for "children" --> objects with ids that start with the parent id
        for(var j=0;j<list.length;j++){
            if (list[j].id.indexOf(parent.id) == 0 && list[j].id != parent.id){
                children.push(list[j]);
            }
        }

        if (children.length){
            // If there's any children, nest those children too
            // Pass the found children as the "list" parameter
            // and the parent's id length as the second (to count periods from that index)
            parent.children = nestChildren(children, parent.id.length + 1);
        }
    }

    return parents;
}

Working JSFiddle here.

【讨论】:

  • 如果层次链中的卡片被移除,则失败。尝试删除 {"id": "card:1.usa.illinios", "name": "illinios"} 并运行你的小提琴
  • @santon 是的,它会失败。我没有意识到层次结构中的卡片可以被删除,这个问题没有任何这种情况......
  • 我同意。问题没有那个。但没有任何东西表明层次结构会存在或关于顺序。
  • @Angela :我也在考虑进行递归调用,但不知道该怎么做。肯定会从您的解决方案中获得提示。
猜你喜欢
  • 2016-07-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 2014-10-23
  • 2018-01-22
相关资源
最近更新 更多