77

I'm starting to explore Scala, and one of the things I'm intrigued by is the Option type and the promise of being able to eliminate null related errors.

However I haven't been able to work out how to transform a list (or other collection) of, say, Option[String], to a collection of String (obviously filtering out any values that are None).

In other words, how do I get from this:

List[Option[Int]] = List(Some(1))

... to this:

List[Int] = List(1)

I'm using Scala 2.8 if that has any impact on the answer.

Jonik
  • 80,077
  • 70
  • 264
  • 372
npad
  • 5,036
  • 4
  • 24
  • 22

2 Answers2

139
val list1 = List(Some(1), None, Some(2))
val list2 = list1.flatten // will be: List(1,2)
Madoc
  • 5,841
  • 4
  • 25
  • 38
  • 9
    It's worth to note though, that it works only because there is an implicit conversion from Option[A] to GenTraversableOnce[A] – mutantacule Apr 15 '15 at 07:20
  • 1
    @kosii Looks like (in Scala 2.11.6 at least) the conversion is from Option[A] to Iterable[A] – Rag Apr 28 '15 at 21:54
58

For educational purposes, you might like some alternatives:

scala> val list1 = List(Some(1), None, Some(2))
list1: List[Option[Int]] = List(Some(1), None, Some(2))

scala> list1 flatten
res0: List[Int] = List(1, 2)

// Expanded to show the implicit parameter
scala> list1.flatten(Option.option2Iterable)
res1: List[Int] = List(1, 2)

scala> list1 flatMap (x => x)
res2: List[Int] = List(1, 2)

scala> list1 flatMap Option.option2Iterable
res3: List[Int] = List(1, 2)

// collect is a simultaneous map + filter
scala> list1 collect { case Some(x) => x }
res4: List[Int] = List(1, 2)

With Scalaz, you can perform a slightly different operation called sequence, that returns Option[List[Int]].

scala> import scalaz._; import Scalaz._
import scalaz._
import Scalaz._

scala> val list1: List[Option[Int]] = List(Some(1), None, Some(2)) 
list1: List[Option[Int]] = List(Some(1), None, Some(2))

scala> list1.sequence                                              
res1: Option[List[Int]] = None

scala> val list2: List[Option[Int]] = List(Some(1), Some(2))         
list2: List[Option[Int]] = List(Some(1), Some(2))

scala> list2.sequence
res2: Option[List[Int]] = Some(List(1, 2))
retronym
  • 54,768
  • 12
  • 155
  • 168