Efficace itération avec index en Scala
Depuis Scala n'a pas old Java style for
boucles avec index,
//does not work
val xs = Array("first", "second", "third")
for (i=0; i<xs.length; i++) {
println("String #" + i + " is " + xs(i))
}
Comment peut-on parcourir efficacement, et sans l'aide de var
s'?
Que vous pourriez faire ce
val xs = Array("first", "second", "third")
val indexed = xs zipWithIndex
for (x <- indexed) println("String #" + x._2 + " is " + x._1)
mais la liste est parcourue deux fois - n'est pas très efficace.
- Ce sont toutes de bonnes réponses. Ce qui me manque de Java "pour" boucles est la possibilité d'avoir plusieurs initialiseurs, et la capacité à "itérer" en utilisant plus que juste incrémente/décrémente. C'est une instance où Java peut être plus concis que Scala.
- ..."itérer" en utilisant plus que juste incrémente/décrémente... En scala, il est possible d'itérer avec l'étape, ou itérer avec des "si" condition dans la boucle d'en-tête. Ou vous cherchez quelque chose d'autre?
- /*Java*/ for(int i=0, j=0; i+j<100; i+=j*2, j+=i+2) {...} Comment pouvez-vous faire cela en 1 ligne en Scala?
- À mon avis, le plus naturel de la traduction à la Scala serait un
while
boucle. Je me souviens, il y avait un débat il y a quelques années si Scala doit hériter de Javafor(;;)
boucle, et il a été décidé que l'avantage n'était pas suffisant pour justifier la complexité ajoutée.
Vous devez vous connecter pour publier un commentaire.
Bien pire que traversent deux fois, il crée un intermédiaire tableau de paires.
Vous pouvez utiliser
view
. Lorsque vous necollection.view
, vous pouvez penser de la suite des appels à agir paresseusement, au cours de l'itération. Si vous souhaitez obtenir de nouveau un bon réalise pleinement collection, vous appelezforce
à la fin. Ici, ce serait inutile et coûteux. Afin de modifier votre code pourList
, le plus utilisé de la collection en Scala) - et pas seulement sur eux. Découvrez laapply
opération ici. Dans une liste, comme la collecte de tous les accès à un élément par les résultats de l'index dans un parcours de la liste.Il a été mentionné que la Scala ne de syntaxe pour
for
boucles:ou tout simplement
Toutefois, il est également demandé pour l'efficacité. Il s'avère que la Scala
for
syntaxe est effectivement sucre syntaxique pour les ordre élevé, des méthodes telles quemap
,foreach
, etc. Ainsi, dans certains cas, ces boucles peuvent être inefficaces, par exemple Comment optimiser pour des inclusions et des boucles en Scala?(La bonne nouvelle est que la Scala équipe est de travailler sur l'amélioration de la ce. Voici la question dans le bug tracker: https://issues.scala-lang.org/browse/SI-4633)
Pour un maximum d'efficacité, on peut utiliser un
while
boucle ou, si vous insistez sur l'élimination des utilisations devar
, la queue de la récursivité:Noter que le facultatif
@tailrec
annotation est utile pour s'assurer que la méthode est en fait la queue récursive. La Scala compilateur traduit la queue-les appels récursifs dans le byte code équivalent de la boucle while.xs
est de toute forme de liste chaînée (comme le largement utiliséList
), de l'accès à ses éléments par index commexs(i)
sera linéaire et donc lafor (i <- xs.indices) println(i + " : " + xs(i))
effectuera de façon pire quefor((x, i) <- xs.zipWithIndex) println(i + " : " + x)
, comme il en résultera beaucoup plus que juste deux traversals sous le capot. Par conséquent, la réponse de @didierd ce qui suggère d'utiliser les points de vue devraient être acceptée comme la plus générale et la plus idiomatique de l'un, de l'OMI.view
est utilisé, ce même haut niveau d'abstraction va mettre plus de pression sur le tas et GC. Dans mon expérience, il est souvent un facteur 10 dans les performances de l'gagné en évitant les tas de répartition en code numérique.D'une façon de plus:
En fait, scala a old Java de style de boucles avec index:
Où
0 until xs.length
ou0.until(xs.length)
est unRichInt
méthode qui renvoie laRange
adapté pour la lecture en boucle.Aussi, vous pouvez essayer de boucle avec
to
:xs(i)
sur les listes soulève la complexité à O(n^2)Comment à ce sujet?
De sortie:
En boucle dans la scala est assez simple.
Créer un tableau de votre choix pour ex.
Types de boucles,
En effet, l'appel de
zipWithIndex
sur une collection de traverse et aussi de créer une nouvelle collection pour les paires. Pour éviter cela, vous pouvez simplement appelerzipWithIndex
sur l'itérateur pour la collection. Ce sera juste de retour d'un nouvel itérateur qui conserve la trace de l'indice lors de l'itération, donc sans la création d'une collection supplémentaire ou additionnelle de la traversée.C'est de cette façon
scala.collection.Iterator.zipWithIndex
est actuellement mis en œuvre dans 2.10.3:Ce devrait même être un peu plus efficace que la création d'un point de vue sur la collection.
Il n'y a rien dans la stdlib qui va le faire pour vous sans la création d'un tuple des ordures, mais il n'est pas trop dur à écrire votre propre. Malheureusement, je n'ai jamais pris la peine de comprendre comment faire le bon CanBuildFrom implicite raindance pour faire de telles choses générique dans le type de collecte auquel ils sont appliqués, mais si c'est possible, je suis sûr que quelqu'un va nous éclairer. 🙂
Quelques moyens pour effectuer une itération:
foreach, et similaires, carte, qui permettrait le retour de quelque chose (les résultats de la fonction, qui est, pour println, Unité, donc une Liste d'Unités)
à travailler avec les éléments, et non pas l'indice
pliage
La partie est juste un exemple, pour faire quelque chose avec i et j. Il n'a pas besoin d'être un Int.
pour des trucs plus simple, plus proche d'habitude pour des boucles:
ou sans ordonnance:
J'ai les approches suivantes
Une manière simple et efficace, inspiré de la mise en œuvre de
transform
dans SeqLike.scalaLes solutions proposées souffrent du fait qu'ils soit explicitement itérer sur une collection ou des objets de la collection dans une fonction. Il est plus naturel de les coller avec de l'habitude de les idiomes de la Scala et de mettre l'index à l'intérieur de la carte d'habitude - ou foreach-méthodes. Cela peut être fait en utilisant memoizing. Le code résultant peut ressembler à
Ici est une façon d'atteindre ce but. Envisager l'utilitaire suivant:
C'est déjà tout ce que vous devez. Vous pouvez appliquer la présente par exemple comme suit:
qui résultats dans la liste
De cette façon, vous pouvez utiliser l'habituel Traversable-fonctions au détriment de l'emballage de votre fonction. Profitez-en!