Search code examples
scalaimplicit-conversionscala-collectionsenrich-my-library

Enriching Scala collections with a method


How do I add a foreachWithIndex method on Scala collections?

This is what I could come up with so far:

implicit def iforeach[A, CC <: TraversableLike[A, CC]](coll: CC) = new {
  def foreachWithIndex[B](f: (A, Int) => B): Unit = {
    var i = 0
    for (c <- coll) {
      f(c, i)
      i += 1
    }
  }
}

This doesn't work:

Vector(9, 11, 34).foreachWithIndex { (el, i) =>
  println(el, i)
}

Raises the following error:

error: value foreachWithIndex is not a member of scala.collection.immutable.Vector[Int]
Vector(9, 11, 34).foreachWithIndex { (el, i) =>

However the code works when I explicitly apply the conversion method:

iforeach[Int, Vector[Int]](Vector(9, 11, 34)).foreachWithIndex { (el, i) =>
  println(el, i)
}

Output:

(9,0)
(11,1)
(34,2)

How do I make it make it work without explicit application of a conversion method? Thanks.


Solution

  • You need to extend Iterable:

    class RichIter[A, C](coll: C)(implicit i2ri: C => Iterable[A]) {
        def foreachWithIndex[B](f: (A, Int) => B): Unit = {
        var i = 0
        for (c <- coll) {
          f(c, i)
          i += 1
        }
      }
    }
    
    implicit def iter2RichIter[A, C[A]](ca: C[A])(
        implicit i2ri: C[A] => Iterable[A]
    ): RichIter[A, C[A]] = new RichIter[A, C[A]](ca)(i2ri)
    
    Vector(9, 11, 34) foreachWithIndex {
      (el, i) => println(el, i)
    }
    

    output:

    (9,0)
    (11,1)
    (34,2)
    

    See this post by Rex Kerr for more information.