Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Summing up two options

Let's say I have two optional Ints (both can be Some or None):

val one : Option[Int] = Some(1)
val two : Option[Int] = Some(2)

My question is the following: Are there any intelligent way to sum them op using Scalas brilliant collection-methods? I realize that I could merge them into a collection, flatten it and use reduceLeftOption like so:

(one :: two :: Nil).flatten.reduceLeftOption(_ + _)     // Some(3)

But, the solution above means creating a new collection, and living in a rich and developed world that takes time from all the other first world activities I might immerse myself into. And in a world where programming gets more and more luxurious for programmers like us, there must be one or more luxurious first world answer(s) to this, right?

Edit: So to spell things out, here are some examples:

If one = Some(1) and two = Some(2) we should have Some(3)

If one = Some(1) and two = None we should have Some(1)

If one = None and two = Some(2) we should have Some(2)

If both one and two are None we should have None, since neither one or two can be summed correctly.

Hope that clarified things :-)

like image 244
Jens Egholm Avatar asked May 01 '13 13:05

Jens Egholm


2 Answers

obligatory scalaz answer is to use the scalaz Option monoid:

scala> one |+| two
res0: Option[Int] = Some(3)

It will do what you want with respect to None:

scala> two |+| None
res1: Option[Int] = Some(2)

scala> none[Int] |+| none[Int]
res2: Option[Int] = None

That none method is a method from scalaz which helps with type inference because instead of returning None <: Option[Nothing] it returns a Option[Int], there is a similar method from Some which returns an Option[A] for any given A instead of a Some[A]:

scala> 1.some |+| 2.some
res3: Option[Int] = Some(3)
like image 113
stew Avatar answered Sep 25 '22 01:09

stew


for (x <-one; y <- two) yield x+y

Or the less readable but strictly equivalent:

one.flatMap{x=>two.map(x+_)}

UPDATE: As your latest edit made quite clear, you only want a None as the result when both the input options are None. In this case I don't think you'll get anything better in terms of simplicity than what you already use. I could shorten it a bit but overall this is just the same:

(one ++ two).reduceOption(_ + _)
like image 41
Régis Jean-Gilles Avatar answered Sep 25 '22 01:09

Régis Jean-Gilles