Since Scala does not have old Java style for
loops with index,
// does not work
val xs = Array("first", "second", "third")
for (i=0; i<xs.length; i++) {
println("String #" + i + " is " + xs(i))
}
How can we iterate efficiently, and without using var
's?
You could do this
val xs = Array("first", "second", "third")
val indexed = xs zipWithIndex
for (x <- indexed) println("String #" + x._2 + " is " + x._1)
but the list is traversed twice - not very efficient.
Looping in scala is pretty simple. Create any array of your choice for ex.
Types of loops,
There's nothing in the stdlib that will do it for you without creating tuple garbage, but it's not too hard to write your own. Unfortunately I've never bothered to figure out how to do the proper CanBuildFrom implicit raindance to make such things generic in the type of collection they're applied to, but if it's possible, I'm sure someone will enlighten us. :)
Indeed, calling
zipWithIndex
on a collection will traverse it and also create a new collection for the pairs. To avoid this, you can just callzipWithIndex
on the iterator for the collection. This will just return a new iterator that keeps track of the index while iterating, so without creating an extra collection or additional traversing.This is how
scala.collection.Iterator.zipWithIndex
is currently implemented in 2.10.3:This should even be a bit more efficient than creating a view on the collection.
The proposed solutions suffer from the fact that they either explicitly iterate over a collection or stuff the collection into a function. It is more natural to stick with the usual idioms of Scala and put the index inside the usual map- or foreach-methods. This can be done using memoizing. The resulting code might look like
Here is a way to achieve this purpose. Consider the following utility:
This is already all you need. You can apply this for instance as follows:
which results in the list
This way, you can use the usual Traversable-functions at the expense of wrapping your effective function. Enjoy!
Actually, scala has old Java-style loops with index:
Where
0 until xs.length
or0.until(xs.length)
is aRichInt
method which returnsRange
suitable for looping.Also, you can try loop with
to
:Some more ways to iterate:
foreach, and similar, map, which would return something (the results of the function, which is, for println, Unit, so a List of Units)
work with the elements, not the index
folding
The carry-part is just some example, to do something with i and j. It needn't be an Int.
for simpler stuff, closer to usual for-loops:
or without order: