Contains a list of options in Scala

How can I summarize the list of options List[Option[Double]] with the following rules?

  • List(Some(1), ..., Some(n)) --> Some(1 + ... + n)
  • List(Some(1), ..., Some(n), None) --> None
  • List(None, ..., None) --> None
+6
source share
4 answers

To avoid traversing the entire list with forall , to check if the entire set of parameters is set, you can use foldLeft and use the fact that you can get None for the first time you find an empty element in the chain.

 def sumList(list: List[Option[T]])(implicit ev: Numeric[T]): Option[T] = { list.foldLeft(Option(ev.zero)) { case (acc, el) => el.flatMap(value => acc.map(ac => ev.plus(ac, value))) } } sumList(List(None, None, Some(5))) res10: Option[Int] = None scala> sumList(List(None, None, Some(5F))) res11: Option[Float] = None scala> sumList[Double](List(None, None, None)) res13: Option[Double] = None scala> sumList(List(Some(5), Some(15))) res14: Option[Int] = Some(20) 

And to avoid return , you can simply use recursion ( update , return is not required above, but it might be easier to do):

 @annotation.tailrec def sumListRec[T](list: List[Option[T]], acc: T)(implicit ev: Numeric[T]): Option[T] = { list match { // if the list still has elements case head :: tail => head match { // add the value to the accumulator and keep going case Some(value) => sumListRec(tail, ev.plus(acc, value)) // if you found a None, disregard whatever sum we built so far // and just return None case None => None } // If the list is empty, it means we've successfully reached // the end of the list, so we just return the sum we built. case Nil => Some(acc) } } 

Watch the action:

 scala> sumListRec(List(Some(5D), Some(5D)), 0D) res5: Option[Double] = Some(10.0) sumListRec(List(None, None, Some(5D)), 0D) res2: Option[Double] = None scala> sumListRec(List(None, None), 0D) res6: Option[Double] = None 
+3
source

If you use Scalaz, it is very simple:

 targetList.sequence.map(_.suml) 
+2
source

You can do it like this. Edit : changed the code to return immediately after meeting None . I admit that this optimization does not complicate the code too much and does not interfere with readability (as I thought before).

 def sumOpt(list: List[Option[Double]]): Option[Double] = list.reduce((x,y) => { if (x.isEmpty || y.isEmpty) return None else Some(x.get + y.get) }) sumOpt(list) 
0
source

There is an even simpler way to use fold:

 val ls = List(Some(2.1d), Some(5.6d), Some(4.3d), Some(1.2)) ls.fold(Option(0d))((rs,x) => for(n <- x; m <- rs) yield {n+m}) 

=> Some (13.2)

 val ls = List(Some(2.1d),None, Some(5.6d), Some(4.3d), Some(1.2)) ls.fold(Option(0d))((rs,x) => for(n <- x; m <- rs) yield {n+m}) 

=> No

0
source

All Articles