Obtenir l’index de l’élément actuel dans une méthode foreach de Traversable?

Supposons que j’ai deux tableaux:

val ar1 = Array[Ssortingng]("1", "2", "3") val ar2 = Array[Ssortingng]("1", "2", "3", "4") 

Maintenant, pour chaque élément de ar1 , je veux d’abord concaténer cet élément avec l’élément correspondant de ar2 , puis imprimer le résultat. Une façon de faire serait quelque chose comme:

 List.range(0, ar1.size).foreach(i => println(ar1(i)+ar2(i))) 

Cela aurait été mieux si une variante de foreach me permettait de travailler directement avec les index de ar1 au lieu de construire d’abord la liste d’entiers.

Peut-être y a-t-il une meilleure façon?

Une méthode très pratique consiste à utiliser la méthode zipped sur les n-uplets. Mettez deux collections, sortez deux arguments pour une fonction!

 (ar1,ar2).zipped.foreach((x,y) => println(x+y)) 

Ceci est à la fois commode pour écrire et rapide, puisque vous n’avez pas besoin de créer un tuple pour stocker chaque paire (comme vous le feriez avec (ar1 zip ar2) ) que vous devez ensuite démonter à nouveau. Les deux formes de zip s’arrêtent lorsque la plus courte des deux collections est épuisée.

Si vous avez quelque chose de plus compliqué (par exemple, vous devez faire des calculs sur l’index), la solution canonique est de compresser l’index:

 ar1.zipWithIndex.foreach{ case(x,i) => println(x+ar2(i)) } 

La méthode que vous utilisez est plus rapide et plus compacte, et peut être utile:

 ar1.indices.foreach(i => println(ar1(i)+ar2(i))) 

Bien que cela ne fonctionne que si la première collection n’est plus que la seconde. Vous pouvez également spécifier explicitement vos plages:

 (0 until (ar1.size min ar2.size)).foreach(i => println(ar1(i)+ar2(i))) 

pour contourner ce problème. (Vous pouvez voir pourquoi zip et zipped sont préférables à moins que ce que vous faites ne soit trop compliqué pour que cela fonctionne facilement.)

S’il ne s’agit pas d’une collection parallèle (et ce n’est généralement pas le cas sauf si vous appelez .par ), il est également possible, mais pas recommandé, de suivre une variable mutable:

 { var i=-1; ar1.foreach{ x => i += 1; println(x+ar2(i)) } } 

Il y a un nombre très limité de cas où cela est nécessaire (par exemple, si vous souhaitez sauter ou revenir en arrière sur certaines des autres collections); Si vous ne pouvez pas le faire, vous obtiendrez généralement un code plus facile à comprendre.

Voici comment vous bouclez avec un index dans Scala idiomatique:

 scala> List("A", "B", "C").zipWithIndex foreach { case(el, i) => | println(i + ": " + el) | } 0: A 1: B 2: C 

Et voici la manière idiomatique Scala de faire ce que vous essayez de réaliser dans votre code:

 scala> val arr1 = Array("1", "2", "3") arr1: Array[java.lang.Ssortingng] = Array(1, 2, 3) scala> val arr2 = Array("1", "2", "3", "4") arr2: Array[java.lang.Ssortingng] = Array(1, 2, 3, 4) scala> (arr1, arr2).zipped.map(_ + _) foreach println 11 22 33 

Je n’ai pas eu l’occasion de le tester, mais cela devrait faire l’affaire:

 ar1.zip(ar2).foreach(x => println(x._1 +x._2)) 

zip fera:

 ar1 zip ar2 foreach { p => println(p._1 + p._2) } 

Cela donnera:

 11 22 33 

Notez que vous n’avez pas besoin du type générique [Ssortingng] , sera indiqué par le compilateur:

 val ar1 = Array("1", "2", "3") val ar2 = Array("1", "2", "3", "4")