2013-11-27 45 views
5

我有一個扁平對象和一個數組,我需要從中構建一個樹狀對象。如何通過對象循環並創建樹對象

choices: ['choice1', 'choice2', 'choice3']; 
items: [ 
    { 
     choice1: 'taste', 
     choice2: 'good', 
     choice3: 'green-lemon' 
    }, 
    { 
     choice1: 'taste', 
     choice2: 'bad', 
     choice3: 'green-lemon' 
    } 
]; 

該數組描述了每個選項將在樹中出現的級別。我不知道稍後會有多少選擇,項目或級別。

如何獲得下列對象:

output: { 
    taste: { 
     good: { 
      green-lemon:1 
     }, 
     bad: { 
      green-lemon:1 
     } 
    } 
} 

我需要說明有多少項目有每個級別上的對象。在這個例子中,這是choice1: 1;choice2: 2和每個choice3: 1

關於如何建立一個循環來得到這樣的結果有什麼建議?

+0

是否有將是比這更水平?這個數據集是否會擴展? –

+0

「選擇」數組旨在描述樹中每個選擇的級別? @ brainwipe的問題也與正確的解決方案有關。 –

+0

@brainwipe:可能只有2個層次的選擇,可能有5個層次的選擇。選擇數組和項目對象在運行時永遠不會改變。 – Dinkheller

回答

2

我覺得這裏最好的解決辦法是用一些遞歸循環。我在示例中增加了模型的大小以顯示它與n級關聯。用你的javascript控制檯檢查輸出。

var choices = ['choice1', 'choice2', 'choice3']; 
var items = [{ 
    choice1: 'taste', 
    choice2: 'good', 
    choice3: 'green-lemon' 
}, { 
    choice1: 'taste', 
    choice2: 'bad', 
    choice3: 'green-lemon' 
}, 
{ 
    choice1: 'taste', 
    choice2: 'ok', 
    choice3: 'green-lemon' 
}, 
{ 
    choice1: 'taste', 
    choice2: 'ok', 
    choice3: 'green-lemon' 
}]; 

function IsLastLevel(levelIndex) { 
    return (levelIndex == choices.length - 1); 
} 

function HandleLevel(currentItem, currentLevel, nextChoiceIndex) { 

    var nextLevelName = currentItem[choices[nextChoiceIndex]]; 

    if (typeof currentLevel[nextLevelName] === 'undefined') { 
     currentLevel[nextLevelName] = {}; 
    } 

    if (IsLastLevel(nextChoiceIndex)) { 
     if (currentLevel[nextLevelName] > 0) { 
      currentLevel[nextLevelName]++; 
     } else { 
      currentLevel[nextLevelName] = 1; 
     } 
    } else { 
     var goOneDeeper = nextChoiceIndex + 1; 
     HandleLevel(currentItem, currentLevel[nextLevelName], goOneDeeper); 
    } 
} 

var output = {}; 

for(var itemIndex in items) 
{ 
    var item = items[itemIndex]; 
    HandleLevel(item, output, 0); 
} 

console.log(output); 

JsFiddle Demo

+0

偉大。非常感謝。 – Dinkheller

0

你能澄清這些數據有什麼關係嗎?

哪裏的「1」的值從這裏來:「綠色萊蒙:1」

什麼是「選擇」陣列的目的是什麼?

+0

'1'表示只有一件產品帶有綠檸檬口味 - >很好。和一個味道 - >不好 – Dinkheller

2

Brainwipe已經給予了非常乾淨的答案,但我想我會盡我的手呢。該解決方案通過遞歸地逐級減少項目列表,直到它到達葉節點。

function choiceTree(items, choices) { 
    // Return empty object if there were no choices. 
    if (!choices.length) return {}; 

    var choice = choices.shift(); 

    // Construct the current level of the tree. 
    var level = items.reduce(function(node, item) { 
     var value = item[choice]; 

     // Add item if branch node or set to 1 if leaf node. 
     node[value] = (choices.length) 
      ? (node[value] || []).concat(item) 
      : 1; 

     return node; 
    }, {}); 

    // Return if there are no remaining choices. 
    if (!choices.length) return level; 

    // Recursively construct the next level. 
    for (var node in level) 
     level[node] = choiceTree(level[node], choices.slice()); 

    return level; 
} 

jsFiddle demo

+0

也非常感謝。這是少代碼,但更難閱讀。我還沒有與減少工作,但肯定會看看它。謝謝。 – Dinkheller

+2

'Array.reduce'真的很酷並且使用不足,你一定要閱讀它! :)它所做的只是將一個數組「減少」爲一個值;你可以[使用'for'循環代替](http://jsfiddle.net/Jordan/j5aXL/),但我認爲額外的代碼更混亂。它在IE 8及以下版本中不受支持,但它很容易(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce#Compatibility)。 –