3

如果我有一个

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"))来过滤我的列表并组合过滤顺序。

4

2 回答 2

5

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

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

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 创建案例类实例。此外,您不必使用 equals 来比较字符串。scala == 运算符将调用equals,而不仅仅是像java == 运算符那样检查引用相等性。

于 2013-07-22T16:01:58.607 回答
1

我有点喜欢使用隐式,所以你可以获得这种语法:

  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")))
于 2013-07-22T16:04:34.103 回答