折叠选项 vs 折叠 Collection
Fold on Option vs Fold on Collection
在 Scala 中,要表达这个:
val opt:Option[String] = Some("a")
if(opt.isEmpty) "" else opt.get
您可以在 Options
上使用此 fold
模式:
opt.fold("")(_)
但是 collection 上的 fold
表现不同。我怎样才能为 collections 实现同样的效果,而不必写:
case class Container(description: String, collection: Seq)
val col = Seq()
if(col.nonEmpty) {
Some(Container("some description", col))
} else {
None
}
也就是说,我怎么才能优雅 return Some()
collection 只有不空的时候才可以
这个有点短,虽然也不是很优雅:
Option(col.nonEmpty).collect { case true => Container("some description", col) }
或者,但 IMO 更丑陋(我刚刚看到 Hüseyin 也建议了):
col.headOption.map(Container("some description", col))
您对 fold
的期望是错误的,这与 Option
无关,而是与集合有关,并且与 Option
一起工作,因为它们也是集合。
使用 fold
时,您将使用第一个参数提供起始值并提供将应用于集合的函数。
关于你的问题:
您共享的代码看起来不错,但是如果您 真的 想要映射某些选项,您可以使用 headOption
并将其映射到您想要的值,但这不会使您的代码更优雅或清除
请注意,Option
和 Seq
的示例并不等同:在前一种情况下,结果是 内部 的值Option
或空字符串,而在后一种情况下,您最终会返回 集合本身 ,而不是其内容。
您也可以对集合使用 fold
执行与 Option
相同的操作,具体取决于您希望如何处理集合中的多个值。例如:
seqOfStrings.foldLeft("") { _ + _ }
会将集合中的所有字符串连接成一个长字符串(使用 seqOfStrings.mkString
可以获得相同的结果)。请注意,这使用 foldLeft
而不是 fold
,因为前者(应该)是可并行的,并且不能保证按顺序处理结果。这是 fold
:
的示例
seqOfInts.fold(0) { _ + _ }
这当然和seqOfInts.sum
一样
fold
(left/right) 的想法是将集合的所有元素组合 ("folding") 为一个值。 Option
是一个特例,因为它只能包含一个元素,所以转换函数不需要接受两个参数,并且看起来很像 getOrElse
的(相反) - 因此你的混乱。
您尝试对集合执行的操作实际上并不是折叠的用例。您可以使用 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)
。
在 Scala 中,要表达这个:
val opt:Option[String] = Some("a")
if(opt.isEmpty) "" else opt.get
您可以在 Options
上使用此 fold
模式:
opt.fold("")(_)
但是 collection 上的 fold
表现不同。我怎样才能为 collections 实现同样的效果,而不必写:
case class Container(description: String, collection: Seq)
val col = Seq()
if(col.nonEmpty) {
Some(Container("some description", col))
} else {
None
}
也就是说,我怎么才能优雅 return Some()
collection 只有不空的时候才可以
这个有点短,虽然也不是很优雅:
Option(col.nonEmpty).collect { case true => Container("some description", col) }
或者,但 IMO 更丑陋(我刚刚看到 Hüseyin 也建议了):
col.headOption.map(Container("some description", col))
您对 fold
的期望是错误的,这与 Option
无关,而是与集合有关,并且与 Option
一起工作,因为它们也是集合。
使用 fold
时,您将使用第一个参数提供起始值并提供将应用于集合的函数。
关于你的问题:
您共享的代码看起来不错,但是如果您 真的 想要映射某些选项,您可以使用 headOption
并将其映射到您想要的值,但这不会使您的代码更优雅或清除
请注意,Option
和 Seq
的示例并不等同:在前一种情况下,结果是 内部 的值Option
或空字符串,而在后一种情况下,您最终会返回 集合本身 ,而不是其内容。
您也可以对集合使用 fold
执行与 Option
相同的操作,具体取决于您希望如何处理集合中的多个值。例如:
seqOfStrings.foldLeft("") { _ + _ }
会将集合中的所有字符串连接成一个长字符串(使用 seqOfStrings.mkString
可以获得相同的结果)。请注意,这使用 foldLeft
而不是 fold
,因为前者(应该)是可并行的,并且不能保证按顺序处理结果。这是 fold
:
seqOfInts.fold(0) { _ + _ }
这当然和seqOfInts.sum
fold
(left/right) 的想法是将集合的所有元素组合 ("folding") 为一个值。 Option
是一个特例,因为它只能包含一个元素,所以转换函数不需要接受两个参数,并且看起来很像 getOrElse
的(相反) - 因此你的混乱。
您尝试对集合执行的操作实际上并不是折叠的用例。您可以使用 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)
。