【问题标题】:Combining Scala Option[Iterable[_]]结合 Scala 选项[Iterable[_]]
【发布时间】:2012-08-05 22:39:02
【问题描述】:

我正在尝试将两个 Option[Iterable[_]] 组合成一个新的 Option[Iterable[_]]。如果其中一个(或两个)元素是 Some ,我想返回 Some ,否则返回 None 。似乎应该有一种惯用的方式来做到这一点,但我似乎找不到。以下似乎可以满足我的要求,但并不是我希望的完美解决方案。

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
}

感谢任何提示。谢谢!

【问题讨论】:

标签: scala collections monads


【解决方案1】:

如果您愿意忍受一些抽象代数,这里有一个很好的概括: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 library 在其 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

(请注意,还有其他操作可以为IterableOption 提供有效的Monoid 实例,但您的操作是最常用的,也是Scalaz 默认提供的。)

【讨论】:

    【解决方案2】:

    这行得通:

    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】:

      您可以将其用于任意数量:

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

      【讨论】:

        猜你喜欢
        • 2010-11-06
        • 1970-01-01
        • 2012-01-04
        • 1970-01-01
        • 2010-11-07
        • 2011-07-26
        • 1970-01-01
        • 1970-01-01
        • 2019-06-25
        相关资源
        最近更新 更多