2017-10-13 2 views
0

J'ai rencontré un type de problème que je ne connais pas en javascript. Je suppose qu'il y a probablement une approche simple pour résoudre ce genre de problème, mais je ne sais pas ce que cela pourrait être.Comment activer une boucle javascript pour itérer récursivement un nombre inconnu de fois?

  • J'ai un tableau qui contient une série d'objets.
  • Chacun de ces objets peut (ou non) contenir un tableau plus profond contenant une série d'objets.
  • Chacun de ces objets peut (ou non) contiennent un tableau plus profond qui contient une série d'objets
  • (et ainsi de suite ...)

je dois traiter chaque objet dans chaque série d'objets, donc écrire un function qui exécute un for loop que je peux invoquer à plusieurs reprises semble l'approche évidente. Mais ... (voici le problème) ... puisque la fonction peut invoquer lui-même un nombre répété de fois, comment puis-je écrire une boucle qui continue à aller plus loin dans l'objet, aussi profond qu'il doit ?

Voici un exemple ...

Avec cet objet:

{ 
    "level1": [ 
    { 
     "FirstItem": "one", 
     "SecondItem": "two", 
     "ThirdItem": [ 
     { 
      "FirstItem": "three", 
      "SecondItem": "four" 
     } 
     ] 
    }, 
    { 
     "FirstItem": "five", 
     "SecondItem": "six", 
     "ThirdItem": [ 
     { 
      "FirstItem": "seven", 
      "SecondItem": "eight" 
     } 
     ] 
    } 
    ] 
} 

je peux enregistrer les valeurs dans l'ordre en utilisant cette boucle imbriquée:

for (var i = 0; i < Object.keys(myObject.level1).length; i++) { 

    for (var j = 0; j < (Object.values(myObject.level1[i]).length); j++) { 

     if (typeof Object.values(myObject.level1[i])[j] === 'string') { 
      console.log(Object.values(myObject.level1[i])[j]); 
     } 

     else { 

      for (var k = 0; k < Object.values(myObject.level1[i])[j].length; k++) { 

       for (var l = 0; l < (Object.values(Object.values(myObject.level1[i])[j][k]).length); l++) { 

        if (typeof Object.values(Object.values(myObject.level1[i])[j][k])[l] === 'string') { 
        console.log(Object.values(Object.values(myObject.level1[i])[j][k])[l]); 
        } 
       } 
      } 
     } 
    } 
} 

Preuve:

var myObject = {}; 
 
myObject['level1'] = []; 
 

 
myObject.level1[0] = {FirstItem: 'one', SecondItem: 'two'}; 
 
myObject.level1[0]['ThirdItem'] = []; 
 

 
myObject.level1[1] = {FirstItem: 'five', SecondItem: 'six'}; 
 
myObject.level1[1]['ThirdItem'] = []; 
 

 
myObject.level1[0].ThirdItem[0] = {FirstItem: 'three', SecondItem: 'four'}; 
 
myObject.level1[1].ThirdItem[0] = {FirstItem: 'seven', SecondItem: 'eight'}; 
 

 
for (var i = 0; i < Object.keys(myObject.level1).length; i++) { 
 

 
    for (var j = 0; j < (Object.values(myObject.level1[i]).length); j++) { 
 

 
     if (typeof Object.values(myObject.level1[i])[j] === 'string') { 
 
      console.log(Object.values(myObject.level1[i])[j]); 
 
     } 
 
    
 
     else { 
 
      
 
      for (var k = 0; k < Object.values(myObject.level1[i])[j].length; k++) { 
 
        
 
       for (var l = 0; l < (Object.values(Object.values(myObject.level1[i])[j][k]).length); l++) { 
 

 
        if (typeof Object.values(Object.values(myObject.level1[i])[j][k])[l] === 'string') { 
 
        console.log(Object.values(Object.values(myObject.level1[i])[j][k])[l]); 
 
        } 
 
       } 
 
      } 
 
     } 
 
    } 
 
}

Mais ... la boucle est absolument horrible. C'est verbeux et laid. Et, s'il était nécessaire d'aller encore plus loin dans l'objet, comment diable trouverait-il alors les itérateurs m, n, o et p?

Je suppose qu'un autre type de boucle (comme while ou do... while) pourrait être une meilleure approche, mais je ne vois pas comment javascript peut déterminer la profondeur de l'objet. En fin de compte, je spécule que c'est juste un exemple d'un modèle que je ne connais pas et j'utilise les mauvais outils, maladroitement, pour produire le bon résultat.

+2

La réponse simple est "utiliser une fonction récursive" - ​​ie. https://www.sitepoint.com/recursion-functional-javascript/ Chaque appel récursif recevra un objet/une collection différent (l'un des éléments enfants de l'objet "racine" de l'appel précédent/parent) sur lequel travailler. – user2864740

Répondre

3
function printValues(inputObj) { 
    for (var key in inputObj) { 
     if (Array.isArray(inputObj[key])) { 
      inputObj[key].forEach(function(currentObj) { 
       printValues(currentObj); 
      }); 
     } else { 
      console.log(inputObj[key]); 
     } 
    } 
} 
+0

Superbe, @Andrea - très impressionnant. 'Array.isArray() 'est nouveau pour moi; Je suis conscient de la boucle 'for in' pour l'énumération des' objets', bien que j'essaie toujours d'en comprendre la raison et que je sois familier avec 'forEach'. Vous avez écrit une fonction très concise et élégante - précisément le genre de chose que j'essayais de construire. Je vous remercie. – Rounin

1

Il s'agit essentiellement d'un arbre (structure de données). Les arbres sont constitués de nœuds parents et enfants. Les nœuds ont chacun une valeur et certains ont une propriété enfant, qui est un tableau d'autres nœuds. J'espère que ce lien aide, https://en.wikipedia.org/wiki/Tree_traversal.