web-dev-qa-db-fra.com

Javascript/angulaire - Boucle en arrière tableau avec forEach

Existe-t-il un moyen de revenir en arrière dans un tableau en utilisant forEach (pas n'importe quel autre type de boucle, je sais faire avec des méthodes for/standard) et sans inverser le tableau lui-même?

14
Mankind1023
var arr = [1, 2, 3];

arr.slice().reverse().forEach(function(x) {
    console.log(x);
})

imprimera:

3
2
1

arr sera toujours [1, 2, 3], la .slice() crée une copie superficielle.

27
naartjie

Non, forEach ne traite que les processus en avant dans le tableau. Il faudrait donc faire autre chose, ce que vous avez dit dans votre question était hors de portée.

Je peux penser à deux options qui utilisent simplement precursors à utiliser forEach (ainsi, ils n’utilisent pas de boucle for ou un autre type de boucle). Je ne sais pas si ceux-ci seraient hors de portée ou non, alors les voici:

  1. Copiez le tableau et inversez la copie, puis utilisez forEach dessus

  2. Utilisez Object.keys pour obtenir les index, inversez-le, puis utilisez forEach dessus (qui parcourt les index, pas les valeurs, mais nous pouvons les rechercher)

Voici # 1:

slice copie le tableau (copie superficielle, donc peu coûteuse), puis nous l'inversons, puis forEach:

var a = ['one', 'two', 'three'];
a.slice().reverse().forEach(function(entry) {
    snippet.log(entry);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Voici # 2:

Nous utilisons Object.keys pour obtenir les index de tableau (en utilisant filter si vous stockez des propriétés non-élément dans vos tableaux), inversez que , puis parcourez le résultat:

var a = ['one', 'two', 'three'];
Object.keys(a).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>


Note latérale: Voici ce que je veux dire à propos de l'utilisation de filter si vous avez des propriétés non-élément sur votre tableau:

var a = ['one', 'two', 'three'];
a.nonElementProperty = "foo";
Object.keys(a).filter(function(name) {
  return String(+name) === name;
}).reverse().forEach(function(index) {
    snippet.log(a[index]);
});
snippet.log("Proof that a is not, itself, reversed: " +
            JSON.stringify(a));
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

8
T.J. Crowder

Ceci peut être accompli de manière relativement concise en utilisant la méthode reverse , la méthode forEach et (si vous utilisez ES6) la flèche

var someArray = ["a","b","c","d"];
someArray.reverse().forEach(arrayItem =>
    console.log(arrayItem)
)

Si vous n'utilisez pas ES6, la solution est à peu près la même, mais sans la fonction de flèche.

var someArray = ["a","b","c","d"];
someArray.reverse().forEach(function(arrayItem) {
    console.log(arrayItem)
})

Les deux vont imprimer sur la console:

d
c    
b
a
4
John

Les navigateurs ne semblent pas encore avoir optimisé la fonction Array.forEach. Avec peu d'effort, vous pouvez écrire un simple polyfill qui exécute la méthode Array.forEach d'au moins 10 à 1.

Vous pouvez donc créer votre propre Array.revEach et le surpasser par rapport au Array.forEach natif, mais je espère que les navigateurs s’attaqueront bientôt à la très lente performance de Array.forEach et rendront inutile la nécessité de polyfiler les méthodes existantes.

For Array.revEach out exécute Array.forEach 17 fois plus rapidement sur "Chrome 46.0.2490.22 beta-m"

if (Array.prototype.revEach === undefined) { 
    Object.defineProperty(Array.prototype, 'revEach', { 
        writable : false,
        enumerable : false,
        configurable : false,
        value : function (func) {
            var i;
            var len = this.length-1;
            for (i = len; i >= 0; i--) {
                func(this[i], i, this);
            }
        }
    });
}

Juste pour ajouter le polyfill officiel réel modifié pour inverser. Les commentaires montrent mes modifications. 

// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
// Modified by Blindman67 to revEach
if (!Array.prototype.revEach) {   // name changed
  Array.prototype.revEach = function(callback, thisArg) { // name changed
    var T;  // k defined where len was
    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }
    var O = Object(this);
    var k = (O.length >>> 0)-1;  // set k (counter) ToUint32
                                 // len var removed
    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }
    if (arguments.length > 1) {
      T = thisArg;
    }
    while (k >= 0) {  // reverse condition
      var kValue;
      if (k in O) {
        kValue = O[k];
        callback.call(T, kValue, k, O);
      }
      k--;  // dec counter
    }
  };
}
2
Blindman67

Il existe une méthode de tableau similaire qui a une partie de compteur inverse, reduce est associé à reduceRight :

const array = ['alpha', 'beta', 'gamma'];

array.reduceRight((_, elem) => console.log(elem), null);

Lorsque vous l'utilisez aux fins demandées, assurez-vous de fournir un deuxième argument. Cela peut être null ou autre chose. Notez également que la fonction de rappel a pour premier argument l'accumulateur, dont vous n'avez pas besoin pour cela.

Si inclure une bibliothèque est une option:

Lodash: forEachRight .

0
trincot

Utilisez simplement une boucle for. Commencez à la fin du tableau et reculez à partir de là.

const array = ['blastoff', 1, 2, 3];

for (let index = array.length - 1; index >= 0; index--) {
  const element = array[index];
  console.log(element);
}

0
Alex K

array.forEach a 3 paramètres. Vous pouvez les utiliser efficacement pour chaque en arrière.

var arr = [1, 2, 3];

    arr.forEach(function(x, index, the_array) {
        let x_prime = the_array[the_array.length-1-index]
        console.log(x_prime);
    })

imprimera

3
2
1
0
grabbag