没有开销的链斯卡拉过滤器

时间:2015-02-20 20:57:25

标签: scala

我想链接一堆过滤器,但不希望与创建多个列表相关的开销。

type StringFilter = (String) => Boolean

def nameFilter(value: String): StringFilter = 
    (s: String) => s == value

def lengthFilter(length: Int): StringFilter = 
    (s: String) => s.length == length

val list = List("Apple", "Orange")

问题是这会在每个过滤器之后构建一个列表:

list.filter(nameFilter("Apples")).filter(lengthFilter(5))

// list of string -> list of name filtered string -> list of name and length filtered string

我想:

// list of string -> list of name and length filtered string

我发现在运行时需要哪些过滤器,所以我必须动态添加过滤器。

// Not sure how to implement add function.
val filterPipe: StringFilter = ???

// My preferred DSL (or very close to it)
filterPipe.add(nameFilter("Apples")
filterPipe.add(lengthFilter(5))

// Must have DSL
list.filter(filterPipe)

如何实施filterPipe

有没有办法在filterPipe(它本身就是一个StringFilter)中以递归方式和过滤条件一起使用?

3 个答案:

答案 0 :(得分:4)

您可以使用withFilter

list.withFilter(nameFilter("Apples")).withFilter(lengthFilter(5))...

答案 1 :(得分:1)

A blog post建议另一种使用隐式类的替代方法,以允许使用自定义运算符聚合多个谓词

implicit class Predicate[A](val pred: A => Boolean) {
  def apply(x: A) = pred(x)

  def &&(that: A => Boolean) = new Predicate[A](x => pred(x) && that(x))
  def ||(that: A => Boolean) = new Predicate[A](x => pred(x) || that(x))
  def unary_! = new Predicate[A](x => !pred(x))
}

然后您可以按如下方式应用谓词链

list.filter { (nameFilter("Apple") && lengthFilter(5)) (_) }

您还可以动态链接谓词

val list = List("Apple", "Orange", "Meat")
val isFruit = nameFilter("Apple") || nameFilter("Orange")
val isShort = lengthFilter(5)

list.filter { (isFruit && isShort) (_) }

正如您所看到的,与withFilter方法相比,此方法的好处是您可以任意组合谓词

答案 2 :(得分:1)

还要考虑过滤器上的view,例如

list.view.filter(nameFilter("Apples")).filter(lengthFilter(5))

这可以防止中间集合,即list中的每个条目都应用后续过滤器。