2013-11-27 15 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

'choices'配列は、各選択肢がツリー内に来るレベルを記述するためのものですか? @ brainwipeの質問は、正しい解決策にも関係しています。 –

+0

@brainwipe:2つのレベルの選択肢があり、5つのレベルの選択肢があるかもしれません。 choices配列とitemsオブジェクトは実行時に決して変更されません。 – 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」は、味が緑 - レモンのアイテムが1つしかない - >良いことを示しています。そして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)です。 –

関連する問題