15

Most SQL implementations (this question has nothing to do with SQL, it is just an example) offer the function COALESCE(x1,x2,...,xn) which returns x1 if it is not NULL, x2 otherwise only if x2 is not NULL neither and so on. If all xi values are NULL then the result is NULL.

I wanted to get something like SQL's COALESCE in Scala for Option values being NULL replaced by None. I'll give you some examples:

> coalesce(None,Some(3),Some(4))
res0: Some(3)

> coalesce(Some(1),None,Some(3),Some(4))
res1: Some(1)

> coalesce(None,None)
res2: None

So I implemented it as:

def coalesce[T](values: Option[T]*): Option[T] = 
    (List[T]() /: values)((prev: List[T], cur: Option[T]) =>
                          prev:::cur.toList).headOption

It works fine but I wonder if already exists something like this function implemented as part of Scala.

  • 1
    Possibly a duplicate of: http://stackoverflow.com/questions/3644154/scala-return-on-first-some-in-list ? – DNA Mar 24 '15 at 13:38

4 Answers4

19

Shorter still, you could use collectFirst. This will do it in one step, with at most one traversal of the collection.

def coalesce[A](values: Option[A]*): Option[A] =
    values collectFirst { case Some(a) => a }


scala> coalesce(Some(1),None,Some(3),Some(4))
res15: Option[Int] = Some(1)

scala> coalesce(None,None)
res16: Option[Nothing] = None
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
11

Auto answer:

The native mechanism (without implementing a coalesce function) is the chaining of calls to orElse method:

> None.orElse(Some(3)).orElse(Some(4))
res0: Option[Int] = Some(3)

> Some(1).orElse(None).orElse(Some(3)).orElse(Some(4))
res1: Option[Int] = Some(1)

> None.orElse(None)
res2: Option[Nothing] = None
7

How about:

values.flatten.headOption

This works since Option is implicitly convertible to Iterable, so flatten works much in the same way as a list of lists.

Ben Reich
  • 16,222
  • 2
  • 38
  • 59
3

Find first defined option:

def coalesce[T](values: Option[T]*): Option[T] =
  values.find(_.isDefined).flatten
Sergii Lagutin
  • 10,561
  • 1
  • 34
  • 43