1
votes

aplatissement d'un tableau avec récursivité

La récursion a été un sujet difficile pour moi jusqu'à présent. En tant que tâche, j'essaie d'écrire un code à partir de zéro en utilisant la récursivité. J'ai écrit cette fonction pour aplatir les tableaux.

function foo(item) {
  if (item instanceof Array) {
    for (let ii of item) {
      foo(ii);
    }
  } else {
    let bar = item;
    console.log(bar);
    return bar;
  }
}

function arrFlatten(arr) {
  let result = [];

  for (let i of arr) {
    let temp = foo(i);
    console.log(temp);
    result.push(temp);
  }

  console.log(result);
  return result;
}

let bar = [1, [2], [3, [[4]]]];
arrFlatten(bar);

J'ai mis 2 console.log () l'un imprime la variable bar et l'autre imprime la variable temp .

Comme vous pouvez le voir en exécutant le code, à l'intérieur du bloc else , bar évalue correctement, mais immédiatement lorsque je le renvoie, la variable temp évalue parfois à non défini .

Je veux comprendre pourquoi cela se produit, je pense qu'il est assez simple de supposer que temp code > évaluera toujours égal à bar.


2 commentaires

Considérez l'autre branche ... Si item est un Array , aucune valeur n'est return ed de foo (i) ...


@tehhowch merci pour la réponse. Je ne prends pas en compte le fait que toutes les fonctions javascript retournent undefined sauf indication contraire.


4 Réponses :


0
votes

Je ne sais pas si je suis autorisé à répondre à mes propres questions ici, mais j'ai trouvé la réponse et je ne veux pas laisser cette question sans réponse.

Comme vous pouvez le voir en exécutant le code, à l'intérieur du bloc else, la barre évalue correctement, mais immédiatement lorsque je la renvoie, la variable temp est parfois évaluée comme indéfinie.

Je veux comprendre pourquoi cela se produit, je pense qu'il est assez simple de supposer que la température évaluera toujours égale à bar.

La raison pour laquelle temp renvoie parfois undefined est que je ne prends pas en compte le fait que toutes les fonctions javascript renvoient undefined sauf si spécifié autrement.

Ceux non définis se produisent à la fin de cette

function foo(item, arr=[]) {
  let result;
  if (item instanceof Array) {
    for (let ii of item) {
      result = foo(ii, arr);
    }
  } else {
    arr.push(item);
    return arr;
  }
  return result;
}


let bar = [1, [2], [3, [[4, 5], 6], 7], 8];
console.log(foo(bar));

à chaque fois que la boucle for se termine et la fin de la fonction est atteinte, la fonction renvoie non défini.

Sachant cela, j'ai dû réécrire le code comme ceci.

function foo(item) {
  if (item instanceof Array) {
    for (let ii of item) {
      foo(ii);
    }
  } else {
    let bar = item;
    console.log(bar);
    return bar;
  }
}

Ce n'est pas la manière la plus élégante, mais cela fait le travail.


0 commentaires

0
votes

Essayez le code ci-dessous, il ne s'agit que d'une modification de votre réponse.

Je pense que ce sera une meilleure façon de le faire et vous le comprendrez plus clairement.

Reportez les commentaires dans le code expliquant pourquoi j'ai effectué ces modifications.

// You don't need a 2nd argument, so remove it
function flatten(items){
       let result = [];

       // for loop should be outside the if statement 
       for(let item of items){
             if(item instanceof Array){
                    // flatten recursively, returned array will contain flattened subarray
                    var flattenedItems = flatten(item);
                    for(let flattenedItem of flattenedItems){
                           // Since flattenedItems are returned by 
                        // a recursive call to this function itself,
                          // it is guaranteed that all the elements of 
                          // flattenedItems will already flatted
                        // So, its safe to directly push it to result
                          result.push(flattenedItem);
                   }
             }
             else{
                     result.push(item);
                     // do not return here as I moved for loop out of the if statement
            }
       }
       return result;
}

console.log(flatten([1, [2], [3, [[4, 5], 6], 7], 8]));

// 1, 2, 3, 4, 5, 6, 7, 8


1 commentaires

merci pour la réponse, cela m'aide beaucoup dans mon apprentissage. Je peux voir que la principale différence est que votre code doit exécuter 2 for loop car vous ne passez pas un tableau comme deuxième argument à. dans mon cas, parce que je passe le tableau comme deuxième argument, je sauvegarde ce deuxième pour boucle . par contre, votre code est plus facile à comprendre que le mien. Merci encore.



0
votes

Vous pouvez tirer parti de certaines des constructions de langage ou des méthodes natives pour annuler l'imbrication des tableaux:

const flatten = arr =>
  arr.flatMap(x =>
    Array.isArray(x) ? flatten(x) : x);

console.log(flatten([1, [2], [3, [[4]]]]));
console.log(flatten([1, [2], [3, [[4, 5], 6], 7], 8]));

Utilisation de l'opérateur de diffusion:

a.flatMap(x => x);
//=> [1,2,3,4]


0 commentaires

0
votes

La raison pour laquelle undefined est imprimé sur la console est que toutes les branches de la fonction foo n'ont pas de valeur de retour. S'il atteint l'instruction if , il renverra undefined (car aucune valeur de retour n'est spécifiée).

Vous pouvez utiliser Array.prototype.flat pour simplifier votre fonction (gardez à l'esprit qu'elle a un support limité). flat ne s'aplatit pas indéfiniment. Cependant, la documentation mentionne des alternatives a >, à partir de laquelle on aplatit récursivement.

function flattenDeep(arr) {
  return arr.reduce(
    (acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), 
    []
  );
}

const bar = [1, [2], [3, [[4]]]];
console.log(flattenDeep(bar));

//to enable deep level flatten use recursion with reduce and concat
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];

function flattenDeep(arr1) {
   return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]


1 commentaires

Si vous souhaitez rendre compatible flattenDeep IE, changez la fonction de flèche en fonction normale.