2016-07-08 14 views
0

在Scala中,来表达这一点:折期权VS折上采集

val opt:Option[String] = Some("a") 
if(opt.isEmpty) "" else opt.get 

您可以Options使用此fold模式:

opt.fold("")(_) 

然而fold在集合行为有所不同。我怎样才能实现藏品一样,而无需编写:

case class Container(description: String, collection: Seq) 
val col = Seq() 
if(col.nonEmpty) { 
    Some(Container("some description", col)) 
} else { 
    None 
} 

换句话说,我怎么能优雅返回Some()收集只有当它是不是空的?

+0

你试过'headOption'吗?或者'headOption.map(无论在哪里)' – maks

+0

另外,'if(opt.isEmpty)“”else opt.get'会更加惯用'opt.getOrElse(“”)' – Dave

+1

为什么if/else不是“优雅”?对我来说,这是完美的发现。如果由于某种原因你不需要'if/else',这里有一种方法:'Some(col).filter(_。nonEmpty).map(c => Container(“some description”,c))' – sjrd

回答

2

请注意,您为OptionSeq的例子并不等同:在前者的情况下,其结果是,这是Option或空字符串值,而在后一种情况下,你最终返回收藏本身,而不是其内容。

根据您想要如何处理集合中的多个值,您可以完成与Option相同的操作,集合中也可以使用fold。例如:

seqOfStrings.foldLeft("") { _ + _ } 

将串接所有集合中的字符串成一个长字符串(你可以得到与seqOfStrings.mkString相同的结果)。请注意,这使用foldLeft而不是fold,因为前者是(应该是)可并行化的,并且不保证按顺序处理结果。下面是fold一个例子:

seqOfInts.fold(0) { _ + _ } 

这是,当然,同样作为seqOfInts.sum

的想法fold(左/右)的组合(“折叠”)的集合中的所有元素成一个单一的价值。Option是一种特殊情况,因为它只能包含一个元素,所以变换函数不需要两个参数,而且看起来很像(与之相反) - 因此会让您感到困惑。

你正在试图对收集进行的操作并不是真正的折叠用例。你可以使用headOption为其他答案建议,或者更好的是,模式匹配:

col match { 
    case Seq() => None 
    case x => Some(Container("some description", x)) 
    } 

你可以把它包装成同伴对象,以便看上去漂亮些:

object Container { 
    def apply[T](seq: Seq[T]) = seq match { 
     case Seq() => None 
     case s => Container("some description", x)) 
    } 
    } 

现在,你可以其他地方只需做Container(seq)

+0

这非常好,我认为容器伴侣对象是最优雅的解决方案。谢谢! 除此之外,我认为它有点愚蠢,有两个函数具有相同的名称,但基于上下文有不同的行为... – mirosval

+0

@mirosval我不确定“不同的行为”是什么意思。该行为实际上完全相同:如果容器为空,则返回初始值,否则将变换应用于内容。 – Dima

0

这是一个有点短,虽然还算不上优雅:

Option(col.nonEmpty).collect { case true => Container("some description", col) } 

或者,但IMO甚至丑陋(我刚才看到侯赛因认为它):

col.headOption.map(Container("some description", col)) 
1

您的期望来自fold是错误的,它不是关于Option它是关于使用集合,它与Option一起使用,因为它们也是集合。

With fold您提供了一个具有第一个参数的起始值并提供了一个将应用于收集的函数。

关于你的问题:你共享 代码看起来不错,但如果你真的映射一些选项,您可以使用headOption并将其映射到的值要但这不会使你的代码更优雅或清除