我有對象與對象JavaScript陣列看起來像這樣:構建從平坦對象陣列的對象圖以JavaScript
的itemId
名稱
parentItemId沒有父< ==頂層項目有空值
我想要構建一個父項包含子項的數組,並且這些子項具有子項數組(如果適用)的圖。
什麼是一個很好的方式去做這件事?
我有對象與對象JavaScript陣列看起來像這樣:構建從平坦對象陣列的對象圖以JavaScript
的itemId
名稱
parentItemId沒有父< ==頂層項目有空值
我想要構建一個父項包含子項的數組,並且這些子項具有子項數組(如果適用)的圖。
什麼是一個很好的方式去做這件事?
function objectGraph(items)
{
var items_by_id = {};
var roots = [];
var i;
// Build an id->object mapping, so we don't have to go hunting for parents
for (i = 0; i < items.length; ++i) {
items_by_id[items[i].itemId] = items[i];
items[i].children = [];
}
for (i = 0; i < items.length; ++i) {
var parentId = items[i].parentItemId;
// If parentId is null, this is a root; otherwise, it's parentId's kid
var nodes = (parentId === null) ? roots : items_by_id[parentId].children;
nodes.push(items[i]);
}
return roots;
}
注意,這個代碼給每個節點的children
財產,這是空的,如果一個節點沒有孩子。我個人覺得它比每個節點更簡單和更一致,可能 - 也許 - 沒有孩子;您可以循環使用children
而不用擔心它是否存在。葉節點將有children.length == 0
。
如果您可以保證您只有一個根,您可以return roots[0];
而不是返回數組。
所以,而不是做如果(孩子)你如果(children.length == 0)...嗯我想這有它的用途,如果你想毯子迭代項目,然後決定是否它的葉子。我通常是這樣做的。 – James
而不是做'if(children)',你會做'if(children.length)'。無論哪種方式都可以正常工作(檢查列表是否存在以及它是否包含任何內容),但後者意味着更少的特殊框架,並且不必擔心是否會出現未定義對象錯誤。如果你願意,你可以像對待任何其他對象一樣處理一個葉節點,並迭代它的孩子;你不會有任何孩子去做任何事情。 :)請注意,DOM的工作原理類似;每個節點都有一個兒童列表,即使該列表是空的。 – cHao
足夠真實,並且firefox(可能所有瀏覽器)都會爲孩子返回0。一個空的DOM元素的長度。我的解決方案也做同樣的事情哈哈。 – James
這有點粗糙,但如果我正確收集您的問題,它應該做的工作。它應該返回一個頂級對象的數組,其正確組織他們的子級。
作爲一個說明,這將適用於N級兒童對象,而不僅僅是一個級別。
var finalArray = [];
var YOUR_RAW_ARRAY = [];
var buildObjectGraph = function(inputArray){
var i = 0, len = inputArray.length;
var returnVal = [];
for(;i<len;i++){
if(inputArray[i].parentItemId === null){
findChildren(inputArray[i], inputArray);
returnVal.push(inputArray[i]);
}
}
var findChildren = function(root){
var i = 0, i2 = 0, len = rawDataArray.length, len2 = 0;
for(;i<len;i++){
if(inputArray[i].parentItemId === root.itemId){
if(root.children){
root.children.push(inputArray[i]);
}else{
root.children = [];
root.children.push(inputArray[i]);
}
}
}
//now call it recursively
len2 = root.children.length;
if(len2 > 0){
for(;i2 < len2; i2++){
findChildren(root.children[i2]);
}
}
};
return returnVal;
};
//Then execute it
finalArray = buildObjectGraph(YOUR_RAW_ARRAY);
嘿非常感謝!有沒有辦法通過刪除RAW數組中已經被推送的項目來進行優化? –
我真的希望在處理過程中'拼接'輸入數組的各個部分,但是因爲這兩個函數都使用了指向'inputArray'的指針,這會真的搞亂了試圖遍歷每個項目的迭代器。另外,查看拼接不同數組以傳遞給'findChildren'函數的性能,您可能不會更好,因爲這可能會產生一些開銷。 最後,檢查數組的'.length'屬性的確會減慢一點(特別是在大數組上)。首先將它緩存在一個變量中然後循環對它進行循環會更好。 – ericb
當您構建「樹木構建器功能」時,您必須確定「頂層事物」是單個項目還是項目數組。既然你說itemS我們去一個數組。不同之處在於你傳入並返回的參數,如果它是一個我們傳遞parentId的數組,那麼我們傳遞該id。
function buildTree(parentId, list) {
var nodes = [];
for (var i=0, l; l = list[i]; i++) {
if (l.parentId === parentId) {
// if you need "myList" intact afterwards remove the next line at the cost of efficiency
list.splice(i, 1); i--;
nodes.push({
id: l.id
,parentId: l.parentId
,name: l.name
,children: buildTree(l.id, list)
});
}
}
return nodes;
}
var myTree = buildTree(null, myList);
你可以嘗試像http://www.jqplot.com/ –
插件嗨約瑟夫,有趣的項目!但我不是指圖表/圖表......只是一個嵌套對象「圖」.. –