Scala collect example

The official scala docs say that collect “builds a new collection by applying a partial function to all elements of this sequence on which the function is defined.”

To understand what this means, it’s helpful to see an example of a partial function used in this way. For instance, we can make a function that returns the original value, but handling different input types. This function takes “Any” and turns it into an Int (hence the signature, [Any, Int]).

Even though the function takes an “Any”, it would fail for many types of values; e.g. floating point values – these Scala will drop out of the final collection. This is pretty handy, because you can guarantee that this won’t error out, and you can guarantee that you only get the types of output you want.

val convertFn: PartialFunction[Any, Int] = { 
  case i: Int => i; 
  case s: String => s.toInt;
  case Some(s: String) => s.toInt 
}
List(0, 1, "2", "3", Some(4), Some("5")).
  collect(convertFn)

List[Int] = List(0, 1, 2, 3, 5)

By contrast, any value we return that isn’t an Int, String, or Some(String) gets knocked out of the list – essentially this does a “map” and a “filter” at the same time.

scala> List(6.5, None, null, Unit).collect(convertFn)
res93: List[Int] = List()

Note, however that this isn’t something that catches errors, it’s actually interrogating the function to determine whether it is defined at a particular point; if not, the function is never called.

To prove this, you can define a function that is not implemented for anything other than ints, and collect will fail:

List(1, "").collect(
  { 
    case i: Int => i; 
    case _ => ??? 
  }
)

scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
  at $anonfun$1.applyOrElse(:8)
  at scala.collection.immutable.List.collect(List.scala:303)
  ... 33 elided