Scala 有条件地过滤序列

Scala 有条件地过滤序列,scala,Scala,假设我有一个选项[A=>Boolean],一个列表[A],以及一些我想对该列表的子集执行的操作集。如果设置了该选项,则我希望先筛选列表,然后应用我的操作。如果没有,那么我想将其应用于整个列表。例如: val a : Option[Int => Boolean] = Option((a : Int) => a % 2 == 0) val b = 1 to 100 我可以轻松做到以下几点: val c = if (a.isDefined) b.filter(a.get) else b

假设我有一个
选项[A=>Boolean]
,一个
列表[A]
,以及一些我想对该列表的子集执行的操作集。如果设置了该选项,则我希望先筛选列表,然后应用我的操作。如果没有,那么我想将其应用于整个列表。例如:

val a : Option[Int => Boolean] = Option((a : Int) => a % 2 == 0)
val b = 1 to 100
我可以轻松做到以下几点:

val c = if (a.isDefined) b.filter(a.get) else b
但是,这涉及调用a.get;太多的条件反射让我无法做到这一点!我也可以这样做:

val c = b.filter(a.getOrElse(_ => true))
这感觉好多了,但现在我不得不为序列中的每一个元素执行第二个(尽管很琐碎)操作。我希望它会被优化,但这仍然感觉不完美


我想要的是没有任何缺陷的东西。感觉应该有一个很好的方法来做这件事-有什么想法吗?

把a改成:

val a : Option[Seq[Int] => Seq[Int]] = Option((a : Seq[Int]) => a.filter(_ % 2 == 0))
val b = 1 to 100
val c = a.getOrElse((f:Seq[Int]) => f)(b)

(请注意,我没有尝试上述方法,但它应该会让您产生想法)

您只需要使用正常的选项处理方法:

a.map(b.filter).getOrElse(b)

基本上与Rex Kerr的解决方案相同,但使用Scalaz的
fold
,使其更加简洁

通常,
x.fold(f,g)
≡ <代码>x.map(f).getOrElse(g)


我个人更喜欢模式匹配的清晰性;这是从您的散文描述到代码的非常直接的翻译:

val c = a match {
  case Some(f) => b.filter(f)
  case None => b
}

啊,这看起来不错!翻转情况以将列表应用于选项,而不是将选项应用于列表的想法使情况变得更好!我知道我错过了什么;出于某种原因,我没有看到扭转局势的想法。这是非常整洁的。但是还有一个原因需要将模式“option.map().getOrElse()”添加到标准库中。“这一直是我拉皮条的第一件事。”达维格里菲斯——的确如此。我还有一个名字叫
fold
(像Scalaz),语法是
o.map(f)。getOrElse(b)
变成
o.fold(b)(f)
val c = a match {
  case Some(f) => b.filter(f)
  case None => b
}