Reputation: 655
My intention is to create a function in Scala which accepts some kind of a dynamic query (similar to case
expressions in pattern matching) and returns matching instances inside a List
. Suppose that the list consists of instances of case class Person
which has few properties with different types. The function should be able to accept a dynamic combination of values for some of the fields, and return matching Person
s. I am specifically looking for a clean solution. One possible ways to use such a function would be to pass an object with an anonymous type as the query (the "pattern"):
def find(?): List<Person> = { ? }
val matches = find(new { val name = "Name"; val gender = Gender.MALE })
Ideally, I would like to develop a clean way of passing conditions, instead of concrete values, but it's not essential. Since I am learning Scala, I am not aware of all the techniques to implement such a thing. In C#, I used an anonymous type (similar to the second line of code above) and dynamic
parameters to achieve something similar. What is a clean and elegant solution in Scala?
Upvotes: 1
Views: 745
Reputation: 395
I'm not sure if this is what you are looking for but let's try it this way:
First, we define Person
as case class Person(name: String, gender: Gender.Value)
where Gender
is an already defined enum.
Then we create a Query
case class which has the same fields, but as options which default to None
, and a method for comparing the query to a person:
case class Query(name: Option[String] = None,
gender: Option[Gender.Value] = None){
def ===(person: Person) = check(person.name, name) &&
check(person.gender, gender)
private def check[T](field: T, q: Option[T]) = field == q.getOrElse(field)
}
Unfortunately, in this solution ===
has to call check
separately for each field. Let's leave it like that for now. Maybe it is sufficient (because, for example, the list of fields will not change).
Note that check
returns true
if the query's option is None
, sot you don't have to pass all fields of the query:
val q = Query(name = Some("Ann")) // the gender is not important
q === Person("Ann", Gender.FEMALE) // returns true
And finally the find
method:
def find(people: List[Person], query: Query) = people.filter(query === _)
Upvotes: 1