9

There's a indexWhere function in Vector that finds the index of a match.

def indexWhere(p: (A) ⇒ Boolean, from: Int): Int
> Finds index of the first element satisfying some predicate after or 
> at some start index.

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Vector

I wrote this function to find all indexes where such a match occurs.

  def getAllIndexesWhere[A,B](as: List[A])(f: (B => Boolean))(g: A => B): Vector[B] = {
    def go(y: List[A], acc: List[Option[B]]): Vector[B] = as match {
      case x :: xs => val result = if (f(g(x))) Some(g(x)) else None
                      go(xs, acc :+ result)
      case Nil => acc.flatten.toVector
    }
    go(as, Nil)
  }

However, is there already a built-in function of a collection?

Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384

1 Answers1

16

zipWithIndex, filter, and map are built-ins that can be combined to get all the indices of some predicate.

Get the indices of the even values in the list.

scala> List(1,2,3,4,5,6,7,8,9,10).zipWithIndex.filter(_._1 % 2 == 0).map(_._2)
res0: List[Int] = List(1, 3, 5, 7, 9)

You can also use collect as @0__ notes.

scala> List(1,2,3,4,5,6,7,8,9,10).zipWithIndex.collect{ case(a,b) if a % 2 == 0 => b}
res1: List[Int] = List(1, 3, 5, 7, 9)
Brian
  • 20,195
  • 6
  • 34
  • 55
  • 3
    You can use `collect`: `collect { case (elem, idx) if pred(elem) => idx }` – 0__ Oct 29 '13 at 17:34
  • Very nice, Brian, thanks. Can you give example, @0__, of `collect`? – Kevin Meredith Oct 29 '13 at 17:35
  • 2
    `(1 to 10).zipWithIndex.collect { case (elem, idx) if elem % 2 == 0 => idx }` – 0__ Oct 29 '13 at 17:36
  • Does zipping with index and remapping carry extra overhead? I imagine vector must already have an index, is this what the zip lets you access, or does it construct a new collection? – Allen Wang Oct 22 '16 at 20:51