List('a','b','c','d').zipWithIndex
. But wait!
Does that not trigger an extra iteration through the collection?. Indeed it does and that is where Views help.
List('a','b','c','d').view.zipWithIndex
When using a view the collection is only traversed when required so there is no performance loss.
Here are some examples of zipWithIndex:
- scala> val list = List('a','b','c','d')
- list: List[Char] = List(a, b, c, d)
- /*
- I like to use functions constructed with case statements
- in order to clearly label the index. The alternative is
- to use x._2 for the index and x._1 for the value
- */
- scala> list.view.zipWithIndex foreach {case (value,index) => println(value,index)}
- (a,0)
- (b,1)
- (c,2)
- (d,3)
- // alternative syntax without case statement
- scala> list.view.zipWithIndex foreach {e => println(e._1,e._2)}
- (a,0)
- (b,1)
- (c,2)
- (d,3)
- /*
- Fold left and right functions have 2 parameters (accumulator, nextValue)
- using a case statement allows you to expand that but watch the brackets!
- */
- scala> (list.view.zipWithIndex foldLeft 0) {case (acc,(value,index)) => acc + value.toInt + index}
- res14: Int = 400
- // alternative syntax without case statement
- scala> (list.view.zipWithIndex foldLeft 0) {(acc,e) => acc + e._1.toInt + e._2}
- res23: Int = 400
- /*
- alternative foldLeft operator. The thing I like about this
- syntax is that it has the initial accumulator value on the left
- in the same position as the accumulator parameter in the function.
- The other thing I like about it is that visually you can see that it starts with
- "" and the folds left
- */
- scala> ("" /: list.view.zipWithIndex) {
- | case (acc, (value, index)) if index % 2 == 0 => acc + value
- | case (acc, _) => acc
- | }
- res15: java.lang.String = ac
- /*
- This example filters based on the index then uses map to remove the index
- force simply forces the view to be processed. (I love these collections!)
- */
- scala> list.view.zipWithIndex.filter { _._2 % 2 == 0 }.map { _._1}.force
- res29: Seq[Char] = List(a, c)