web-dev-qa-db-fra.com

Obtenir le compteur/index de boucle en utilisant pour… la syntaxe en JavaScript

Mise en garde:

la question s'applique toujours aux boucles for…of.> N'utilisez pas for…in pour parcourir un Array , utilisez-le pour itérer. sur les propriétés d'un objet. Cela dit, cela


Je comprends que la syntaxe de base for…in en JavaScript ressemble à ceci:

for (var obj in myArray) {
    // ...
}

Mais comment puis-je obtenir la boucle counter/index

Je sais que je pourrais probablement faire quelque chose comme:

var i = 0;
for (var obj in myArray) {
    alert(i)
    i++
}

Ou même le bon vieux:

for (var i = 0; 1 < myArray.length; i++) {
    var obj = myArray[i]
    alert(i)
}

Mais je préférerais utiliser la boucle for-in plus simple. Je pense qu'ils ont l'air mieux et ont plus de sens.

Y a-t-il un moyen plus simple ou plus élégant?


En Python c'est facile:

for i, obj in enumerate(myArray):
    print i
171
hobbes3

for…in effectue une itération sur les noms de propriétés, et non sur les valeurs, et le fait dans un ordre non spécifié (oui, même après ES6). Vous ne devriez pas l'utiliser pour parcourir des tableaux. Pour eux, il existe une méthode forEach dans ES5 qui transmet à la fois la valeur et l’index à la fonction que vous lui attribuez:

var myArray = [123, 15, 187, 32];

myArray.forEach(function (value, i) {
    console.log('%d: %s', i, value);
});

// Outputs:
// 0: 123
// 1: 15
// 2: 187
// 3: 32

Ou de Array.prototype.entries de ES6, qui prend désormais en charge les versions actuelles du navigateur:

for (const [i, value] of myArray.entries()) {
    console.log('%d: %s', i, value);
}

Pour les iterables en général (où vous utiliseriez une boucle for…of au lieu d'un for…in), il n'y a rien d'intégré, cependant:

function* enumerate(iterable) {
    let i = 0;

    for (const x of iterable) {
        yield [i, x];
        i++;
    }
}

for (const [i, obj] of enumerate(myArray)) {
    console.log(i, obj);
}

demo

Si vous vouliez réellement dire for…in - énumération des propriétés - vous auriez besoin d'un compteur supplémentaire. Object.keys(obj).forEach pourrait fonctionner, mais il ne comprend que les propriétés propres; for…in inclut les propriétés énumérables n'importe où sur la chaîne de prototypes.

312
Ry-

Dans ES6, il est bon d'utiliser for-of loop . Vous pouvez obtenir un index pour de of this

for (let [index, val] of array.entries()) {
        // your code goes here    
}

Notez que Array.entries() renvoie un itérateur , ce qui lui permet de fonctionner dans la boucle for-of; ne confondez pas ceci avec Object.entries () , qui retourne un array de paires clé-valeur. 

94
rushUp

Des boucles répétitives parcourent les propriétés d'un objet. Ne les utilisez pas pour les tableaux, même s'ils fonctionnent parfois.

Les propriétés des objets n'ont alors aucun index, elles sont toutes égales et ne doivent pas nécessairement être exécutées dans un ordre déterminé. Si vous voulez compter les propriétés, vous devrez configurer le compteur supplémentaire (comme vous l'avez fait dans votre premier exemple).

boucle sur un tableau:

var a = [];
for (var i=0; i<a.length; i++) {
    i // is the index
    a[i] // is the item
}

boucle sur un objet:

var o = {};
for (var prop in o) {
    prop // is the property name
    o[prop] // is the property value - the item
}
12
Bergi

Que dis-tu de ça

let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log(`${index}:${number}`))

array.forEach cette méthode a un paramètre index qui correspond à l'index de l'élément en cours de traitement dans le tableau.

9
Sanjay Shr

Comme d'autres l'ont déjà dit, vous ne devriez pas utiliser for..in pour parcourir un tableau.

for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }

Si vous voulez une syntaxe plus propre, vous pouvez utiliser forEach:

myArray.forEach( function ( val, i ) { ... } );

Si vous souhaitez utiliser cette méthode, veillez à inclure le module d'extension ES5 pour ajouter la prise en charge des navigateurs plus anciens.

5
Robert Messerle

Voici une fonction eachWithIndex qui fonctionne avec tout ce qui est itérable.

Vous pouvez également écrire une fonction similaire eachWithKey qui fonctionne avec des objets utilisant for...in.

// example generator (returns an iterator that can only be iterated once)
function* eachFromTo(start, end) { for (let i = start; i <= end; i++) yield i }

// convers an iterable to an array (potential infinite loop)
function eachToArray(iterable) {
    const result = []
    for (const val of iterable) result.Push(val)
    return result
}

// yields every value and index of an iterable (array, generator, ...)
function* eachWithIndex(iterable) {
    const shared = new Array(2)
    shared[1] = 0
    for (shared[0] of iterable) {
        yield shared
        shared[1]++
    }
}

console.log('iterate values and indexes from a generator')
for (const [val, i] of eachWithIndex(eachFromTo(10, 13))) console.log(val, i)

console.log('create an array')
const anArray = eachToArray(eachFromTo(10, 13))
console.log(anArray)

console.log('iterate values and indexes from an array')
for (const [val, i] of eachWithIndex(anArray)) console.log(val, i)

La bonne chose avec les générateurs est qu'ils sont paresseux et peuvent prendre comme argument le résultat d'un autre générateur.

0
Rivenfall

C'est ma version d'un itérateur composite qui donne un index et la valeur de toute fonction génératrice passée avec un exemple de recherche principale (lente):

const eachWithIndex = (iterable) => {
  return {
    *[Symbol.iterator]() {
      let i = 0
      for(let val of iteratable) {
        i++
          yield [i, val]
      }
    }
  }

}

const isPrime = (n) => {
  for (i = 2; i < Math.floor(Math.sqrt(n) + 1); i++) {
    if (n % i == 0) {
      return false
    }
  }
  return true
}

let primes = {
  *[Symbol.iterator]() {
    let candidate = 2
    while (true) {
      if (isPrime(candidate)) yield candidate
        candidate++
    }
  }
}

for (const [i, prime] of eachWithIndex(primes)) {
  console.log(i, prime)
  if (i === 100) break
}
0
akurtser