2011-11-10 53 views
27

Estoy tratando de iterar a través de un objeto anidado para recuperar un objeto específico identificado por una cadena. En el objeto de ejemplo siguiente, la cadena de identificador es la propiedad "etiqueta". No puedo entender cómo iterar a través del árbol para devolver el objeto apropiado. Cualquier ayuda o sugerencia sería muy apreciada.Iterar a través de objetos anidados de 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

posible duplicado de [Atraviesa todos los nodos de un árbol de objetos JSON con JavaScript] (http://stackoverflow.com/questions/722668/traverse-all-the-nodes-of-a-json-object-tree- with-javascript) –

+0

¿Desea buscar en todos los niveles del objeto una etiqueta arbitraria? (Aja, polo transversal, esa era la palabra que estaba buscando). – Dave

+0

Posible duplicado de [Objetos de acceso/proceso (anidados), matrices o JSON] (http://stackoverflow.com/questions/11922383/access-process-nested -objects-arrays-or-json) – Liam

Respuesta

34

Se puede crear una función recursiva como este para hacer una profundidad -primera travesía del objeto 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; 
}; 

que puede ser llamado como tal

findObjectByLabel(car, "Chevrolet"); 
+0

En la publicación original, los sub-autos no son propiedades del objeto del automóvil, sino que están contenidos en una matriz 'subs'. –

+0

@JamesClark Lo sé. Todavía debería funcionar, y es flexible en caso de que tenga más de una propiedad de matriz si decide cambiar el nombre de 'subs' por otra cosa. –

+1

La recursividad es mala para objetos muy profundos. Obtendrás desbordamiento de pila. –

2

El código siguiente se supone no hay referencias circulares, y asume subs siempre es una matriz (y no nulo en los nodos hoja):

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

Para aumentar el rendimiento de manipulación adicional árbol es bueno para transformar vista en árbol a la vista de recogida de línea, al igual que [obj1, obj2, obj3]. Puede almacenar relaciones de objetos padre-hijo para navegar fácilmente al alcance padre/hijo.

Buscar el elemento dentro de la colección es más eficiente que encontrar el elemento dentro del árbol (recursión, creación de función dinámica adicional, cierre).

0

modificar en Peter Olson 's respuesta: https://stackoverflow.com/a/8085118

  1. puede evitar el valor de cadena !obj || (typeof obj === 'string'
  2. puede personalizar su clave

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

Aquí es un muerto- método simple usando solo 3 variables ingenio hout recursión.

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

Si usted tiene un problema con las referencias circulares (valores de ejemplo que tenga un objeto de un ser propio objeto A en como el objeto A contiene en sí), o sólo tiene las llaves a continuación, la siguiente solución más lenta que está disponible.

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

Dado que estos métodos no utiliza ningún tipo de recursión de cualquier tipo, estas funciones son muy adecuadas para áreas en las que pueda tener miles de niveles de profundidad.

Cuestiones relacionadas