2011-11-10 10 views
27

文字列で識別される特定のオブジェクトを取得するためにネストされたオブジェクトを反復処理しようとしています。以下のサンプルオブジェクトでは、識別子文字列は「ラベル」プロパティです。適切なオブジェクトを返すためにツリーを反復する方法を頭の中で包み込むことはできません。どんな助けや提案も大歓迎です。ネストされたJavaScriptオブジェクトを反復する

var cars = 
    { 
     label: 'Autos', 
     subs: 
      [ 
       { 
        label: 'SUVs', 
        subs: [] 
       }, 
       { 
        label: 'Trucks', 
        subs: [ 
           { 
           label: '2 Wheel Drive', 
           subs: [] 
           }, 
           { 
           label: '4 Wheel Drive', 
           subs: [ 
              { 
              label: 'Ford',           
              subs: [] 
              }, 
              { 
              label: 'Chevrolet', 
              subs: []          
              } 
             ]       
           } 
          ]  
       }, 
       { 
        label: 'Sedan', 
        subs: [] 
       } 
      ] 
    } 
+1

[JavaScriptを使用したJSONオブジェクトツリーのすべてのノードをトラバースする](http://stackoverflow.com/questions/722668/traverse-all-the-nodes-of-a-json-object-tree- with-javascript) –

+0

オブジェクトのすべてのレベルで任意のラベルを検索したいですか? (Aha、traverse、それは私が探していた言葉でした) – Dave

+0

[アクセス/プロセス(入れ子にされた)オブジェクト、配列、JSON]の重複の可能性があります(http://stackoverflow.com/questions/11922383/access-process-nested -objects-arrays-or-json) – Liam

答えて

34

あなたは深さを行うには、このような再帰関数を作成することができます最初のcarsオブジェクトの横断。さらにツリー操作のパフォーマンスを向上させるためにそう

findObjectByLabel(car, "Chevrolet"); 
+0

元の投稿では、サブカーはカーオブジェクトのプロパティではなく、 'subs'配列に含まれています。 –

+0

@JamesClark私は知っています。それでも動作するはずです。もし、彼が 'subs 'の名前を何か他のものに変更することを決めた場合、複数の配列プロパティを持っている場合には柔軟性があります。 –

+1

非常に深いオブジェクトでは再帰が悪いです。スタックのオーバーフローが発生します。 –

2

次のコード何の循環参照を負いません、とsubsは常に(リーフノードではなくヌル)の配列である前提としています

function find(haystack, needle) { 
    if (haystack.label === needle) return haystack; 
    for (var i = 0; i < haystack.subs.length; i ++) { 
    var result = find(haystack.subs[i], needle); 
    if (result) return result; 
    } 
    return null; 
} 
2

のように呼び出すことができます

var findObjectByLabel = function(obj, label) { 
    if(obj.label === label) { return obj; } 
    for(var i in obj) { 
     if(obj.hasOwnProperty(i)){ 
      var foundLabel = findObjectByLabel(obj[i], label); 
      if(foundLabel) { return foundLabel; } 
     } 
    } 
    return null; 
}; 

[OBJ1、OBJ2、OBJ3]のように、ライン・コレクション・ビューにツリービューを変換する良いです。親子オブジェクトの関係を保存して、親/子スコープに簡単にナビゲートすることができます。

コレクション内の要素を検索する方が効率的です。次にツリー内の要素を見つけます(再帰、追加動的関数の作成、クロージャ)。

0

ピーター・オルソンの答えからの変更:https://stackoverflow.com/a/8085118

  1. 文字列値!obj || (typeof obj === 'string'
  2. を回避することができますここですることができますカスタムあなたの鍵

var findObjectByKeyVal= function (obj, key, val) { 
    if (!obj || (typeof obj === 'string')) { 
    return null 
    } 
    if (obj[key] === val) { 
    return obj 
    } 

    for (var i in obj) { 
    if (obj.hasOwnProperty(i)) { 
     var found = findObjectByKeyVal(obj[i], key, val) 
     if (found) { 
     return found 
     } 
    } 
    } 
    return null 
} 
0

がデッドであります3つの変数だけを使った簡単な方法hout再帰。

function forEachNested(O, f){ 
    O = Object.values(O); 
    var cur; 
    while (O.length){ 
     cur = O.pop() 
     f(cur); 
     if (typeof cur === 'object' && cur.constructor === Object) 
      O.push.apply(O, Object.values(cur)); 
    } 
} 

あなたが循環参照(例えば、オブジェクトAは、それ自体が含まれているように、オブジェクトAの値は、そのような中、オブジェクトA自身であること持つ)に問題がある、またはあなただけのキーを必要とする場合は、次のように遅いソリューションが提供されています。

function forEachNested(O, f){ 
    O = Object.entries(O); 
    var cur; 
    function applyToEach(x){return cur[1][x[0]] === x[1]} 
    while (O.length){ 
     cur = O.pop(); 
     f(cur[0], cur[1]); 
     if (typeof cur[1] === 'object' && cur[1].constructor === Object && 
      !O.some(applyToEach)) 
      O.push.apply(O, Object.entries(cur[1])); 
    } 
} 

これらの方法では、いかなる種類の再帰を使用しないため、これらの関数を使用すると、深さのレベルの数千を持っている可能性がある分野に適しています。

関連する問題