使用动态过滤器参数过滤List

时间:2013-07-22 15:47:59

标签: scala

如果我有

case class User(var firstName: String, var lastName: String, var city: String)

和一个清单

val users = List(
  new User("Peter", "Fox", "Berlin"),
  new User("Otto",  "Schmidt", "Berlin"),
  new User("Carl",  "Schmidt", "Berlin"),
  new User("Hans",  "Schmidt", "Berlin"),
  new User("Hugo",  "Schmidt", "Berlin"))

定义一些东西

val test1 = (user:User,key:String) => user.lastName.equals(key)
val test2 = (user:User,key:String) => user.firstName.startsWith(key)

并过滤

val test = users.filter(u => {
  test1(u,"Schmidt") && test2(u,"H")
})

这很好用。但是,如何生成过滤test1,test2 ... testn动态形成列表的东西呢?我想要预先定义很多过滤条件,并将它们组合到一个条件(如test1(u,“Schmidt”)&& test2(u,“H”))来过滤我的列表并组合过滤顺序。

2 个答案:

答案 0 :(得分:5)

基本上你想要的是一种组合谓词的方法。在这种情况下,谓词是一个接受用户并返回布尔值的函数。所以类型只是User =>布尔

首先,我将重新制定您的“谓词生成器方法”,以便您可以生成谓词。在一些辅助对象里面:

object UserPredicates {
  def lastNameEquals(value:String)(user:User) = user.lastName == value
  def firstNameStartsWith(value:String)(user:User) = user.firstName.startsWith(value)
  ..
}

要生成谓词firstName以“H”开头,您可以部分应用firstNameStartsWith方法,如下所示:

import UserPredicates._
val p1: User => Boolean = firstNameStartsWith("H")

然后通过定义组成谓词的方法,从多个谓词创建谓词非常简单。也许也在UserPredicates中:

 def and(predicates:Seq[User => Boolean])(user:User) = predicates.forall(predicate => predicate(user))
 def or(predicates:Seq[User => Boolean)(user:User) = predicates.exists(predicate => predicate(user))

然后你可以做

import UserPredicates._
val condition1 = firstNameStartsWith("H")
val condition2 = lastNameEquals("Schmidt")
val combined = and(Seq(condition1, condition2))
users.filter(combined)

或简短

users.filter(and(firstNameStartsWith("H"), lastNameEquals("Schmidt")))

顺便说一下:你不应该使用new来创建case类实例。此外,您不必使用equals来比较字符串。 scala ==运算符将调用equals,而不仅仅是检查引用相等性,如java ==运算符。

答案 1 :(得分:1)

我有点像使用implicits所以你可以得到这种语法:

  case class User(var firstName: String, var lastName: String, var city: String)

  val users = List(
    new User("Peter", "Fox", "Berlin"),
    new User("Otto", "Schmidt", "Berlin"),
    new User("Carl", "Schmidt", "Berlin"),
    new User("Hans", "Schmidt", "Berlin"),
    new User("Hugo", "Schmidt", "Berlin"))

  //Note that these are curried now
  val filterLastName = (key: String) => (user: User) => user.lastName.equals(key)
  val filterFirstNameFirstChars = (key: String) => (user: User) => user.firstName.startsWith(key)

  implicit class FilterHelper[A](l: List[A]) {
    def filter(filters: List[A => Boolean]): List[A] = {
      l.filter(a => filters.forall(f => f(a)))
    }
  }

  //implicit filter takes a list of user predicates
  val test = users.filter(List(
    filterLastName("Schmidt"),
    filterFirstNameFirstChars("H")))