有条件地过滤序列

时间:2012-02-07 17:23:36

标签: scala

假设我有一个Option[A => Boolean],一个List[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))

这感觉更好,但现在我仍然坚持为我序列的每个元素执行第二次(尽管是微不足道的)操作。我希望它会被优化,但这仍然感觉不完美。

我想要的是缺少任何缺陷的东西。感觉应该有一个很好的方法 - 任何想法?

4 个答案:

答案 0 :(得分:10)

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

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

答案 1 :(得分:3)

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

一般来说,x.fold(f, g)x.map(f).getOrElse(g)

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> a.fold(b.filter, b)
res112: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100)

答案 2 :(得分:1)

如何将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)

(注意我没有尝试过上述内容,但它应该给你一个想法)

答案 3 :(得分:1)

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

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