Prenons un exemple de mappage simple:
val a = Array("One", "Two", "Three")
val b = a.map(s => myFn(s))
Ce dont j'ai besoin, c'est d'utiliser non pas myFn(s: String): String
ici, mais myFn(s: String, n: Int): String
, où n
serait l'index de s
dans a
. Dans ce cas particulier, myFn s'attendrait à ce que le deuxième argument soit 0 pour s == "One", 1 pour s == "Two" et 2 pour s == "Three". Comment puis-je atteindre cet objectif?
Cela dépend si vous voulez la commodité ou la vitesse.
Lent:
a.zipWithIndex.map{ case (s,i) => myFn(s,i) }
Plus rapide:
for (i <- a.indices) yield myFn(a(i),i)
{ var i = -1; a.map{ s => i += 1; myFn(s,i) } }
Peut-être plus rapide:
Array.tabulate(a.length){ i => myFn(a(i),i) }
Sinon, c'est sûrement:
val b = new Array[Whatever](a.length)
var i = 0
while (i < a.length) {
b(i) = myFn(a(i),i)
i += 1
}
(Dans Scala 2.10.1 avec Java 1.6u37, si "peut-être le plus rapide" est déclaré pour prendre 1x fois le temps pour une opération de chaîne triviale (troncature d'un long chaîne à quelques caractères), puis "lent" prend 2x plus longtemps, "plus rapide" prend 1,3 fois plus longtemps et "sûrement" ne prend que 0,5 fois le temps.)
Un conseil général: utilisez .iterator
méthode généreusement, pour éviter la création de collections intermédiaires, et ainsi accélérer votre calcul. (Uniquement lorsque les exigences de performance l'exigent. Sinon, non.)
scala> def myFun(s: String, i: Int) = s + i
myFun: (s: String, i: Int)Java.lang.String
scala> Array("nami", "zoro", "usopp")
res17: Array[Java.lang.String] = Array(nami, zoro, usopp)
scala> res17.iterator.zipWithIndex
res19: Java.lang.Object with Iterator[(Java.lang.String, Int)]{def idx: Int; def idx_=(x$1: Int): Unit} = non-empty iterator
scala> res19 map { case (k, v) => myFun(k, v) }
res22: Iterator[Java.lang.String] = non-empty iterator
scala> res22.toArray
res23: Array[Java.lang.String] = Array(nami0, zoro1, usopp2)
Gardez à l'esprit que les itérateurs sont mutables, et donc une fois consommés ne peuvent pas être réutilisés.
Un côté: l'appel map
ci-dessus implique le découplage puis l'application de fonction. Cela force l'utilisation de certaines variables locales. Vous pouvez éviter cela en utilisant une sorcellerie d'ordre supérieur - convertissez une fonction régulière en celle qui accepte Tuple, puis passez-la à map
.
scala> Array("nami", "zoro", "usopp").zipWithIndex.map(Function.tupled(myFun))
res24: Array[Java.lang.String] = Array(nami0, zoro1, usopp2)
Et ça? Je pense que ça devrait être rapide et c'est joli. Mais je ne suis pas expert en Scala ...
a.foldLeft(0) ((i, x) => {myFn(x, i); i + 1;} )