2011-11-10 18 views
27

Sto provando a ripetere un oggetto nidificato per recuperare un oggetto specifico identificato da una stringa. Nell'oggetto campione sottostante, la stringa identificatore è la proprietà "label". Non riesco a capire come iterare attraverso l'albero per restituire l'oggetto appropriato. Qualsiasi aiuto o suggerimento sarebbe molto apprezzato.Iterate attraverso gli oggetti JavaScript nidificati

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

possibile duplicato di [Attraversa tutti i nodi di un albero oggetti JSON con JavaScript] (http://stackoverflow.com/questions/722668/traverse-all-the-nodes-of-a-json-object-tree- with-javascript) –

+0

Stai cercando tra tutti i livelli dell'oggetto per un'etichetta arbitraria? (Aha, traverse, era la parola che stavo cercando) – Dave

+0

Possibile duplicato di [Accesso/elaborazione (nidificati) oggetti, matrici o JSON] (http://stackoverflow.com/questions/11922383/access-process-nested -objects-array-or-json) – Liam

risposta

34

è possibile creare una funzione ricorsiva come questo per fare una profondità -primo traversamento dell'oggetto cars.

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; 
}; 

che può essere chiamato in questo modo

findObjectByLabel(car, "Chevrolet"); 
+0

Nel post originale, le sotto-vetture non sono proprietà dell'oggetto auto, ma sono contenute in una matrice 'subs'. –

+0

@JamesClark Lo so. Dovrebbe comunque funzionare, ed è flessibile nel caso in cui abbia più di una proprietà di array se decide di cambiare il nome di 'subs' in qualcos'altro. –

+1

La ricorsione è dannosa per oggetti molto profondi. Otterrai uno stack overflow. –

2

Il codice seguente presuppone riferimenti circolari, e assume subs è sempre un array (e non nullo in nodi foglia):

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

Per aumentare le prestazioni per ulteriori manipolazioni albero è buono per trasformare visualizzazione struttura in vista raccolta linea, come [obj1, obj2, obj3]. È possibile memorizzare le relazioni oggetto padre-figlio per spostarsi facilmente verso l'ambito genitore/figlio.

La ricerca di un elemento all'interno della raccolta è più efficiente quindi trova l'elemento all'interno dell'albero (ricorsione, aggiunta di funzione dinamica, chiusura).

0

modificare dalla risposta Peter Olson s': https://stackoverflow.com/a/8085118

  1. può evitare di valore stringa !obj || (typeof obj === 'string'
  2. possibile personalizzato la vostra chiave

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

Ecco uno scadenze metodo semplice usando solo 3 variabili hout ricorsione.

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)); 
    } 
} 

Se ha un problema con riferimenti circolari (valori esempio avente oggetto di un essere oggetto stesso A come quella oggetto A si contiene), o semplicemente bisogno i tasti quindi la seguente soluzione più lento è disponibile.

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])); 
    } 
} 

Dal momento che questi metodi non utilizza alcun ricorsione di qualsiasi tipo, queste funzioni sono particolarmente adatte per le aree in cui si potrebbe avere migliaia di livelli di profondità.

Problemi correlati