Combining Scala Option [Iterable [_]]

I am trying to combine the two Option[Iterable[_]]into a new one Option[Iterable[_]]. I would like to return Some if one (or both) of the elements is Some and a None otherwise. There seems to be an idiomatic way to do this, but I can't find it. The following seems to do what I want, but not quite what I was hoping for.

def merge(
    i1: Option[Iterable[_]], i2: Option[Iterable[_]]
): Option[Iterable[_]] = (i1, i2) match {
   case (Some(as), Some(bs)) => Some(as ++ bs)
   case (a @ Some(as), None) => a
   case (None, b @ Some(bs)) => b
   case _ => None
}

Any advice is appreciated. Thank!

+5
source share
3 answers

, : Iterable[_] - monoid , - ( ) () ( ).

, A , Option[A] merge:

Some(xs) + Some(ys) == Some(xs + ys)
Some(xs) + None     == Some(xs)
None     + Some(ys) == Some(ys)
None     + None     == None

(, , A , , .)

Scalaz Monoid, merge :

import scalaz._, Scalaz._

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]) = i1 |+| i2

, :

scala> merge(Some(1 to 5), None)
res0: Option[Iterable[_]] = Some(Range(1, 2, 3, 4, 5))

scala> merge(Some(1 to 5), Some(4 :: 3 :: 2 :: 1 :: Nil))
res1: Option[Iterable[_]] = Some(Vector(1, 2, 3, 4, 5, 4, 3, 2, 1))

scala> merge(None, None)
res2: Option[Iterable[_]] = None

( , , Monoid Iterable Option, , , Scalaz .)

+11

:

def merge(i1: Option[Iterable[_]], i2: Option[Iterable[_]]): Option[Iterable[_]] =
  (for (a <- i1; b <- i2) yield a ++ b).orElse(i1).orElse(i2)

for/yield , Some.

, :

  (for (a <- i1; b <- i2) yield a ++ b) orElse i1 orElse i2
+3

You can use this for arbitrary arity:

def merge(xs: Option[Iterable[_]]*) = 
  if (xs.forall(_.isEmpty)) None else Some(xs.flatten.flatten)
+1
source

All Articles