I have a code such as:
val strs = List("hello", "andorra", "trab", "world")
def f1(s: String) = !s.startsWith("a")
def f2(s: String) = !s.endsWith("b")
val result = strs.filter(f1).filter(f2)
now, f1 and f2 should be applied based on a condition, such as:
val tmp1 = if (cond1) strs.filter(f1) else strs
val out = if (cond2) tmp1.filter(f2) else tmp1
is there a nicer way to do this, without using a temporary variable tmp1
?
one way would to filter based on a list of functions, such as:
val fs = List(f1 _,f2 _)
fs.foldLeft(strs)((fn, list) => list.filter(fn))
but then I would need to build a list of functions based on the conditions (and so, I would move the problem of using a temporary string list variable, to using a temporary function list variable (or I should need to use a mutable list)).
I am looking something like this (of course this does not compile, otherwise I would already have the answer to the question):
val result =
strs
.if(cond1, filter(f1))
.if(cond2, filter(f2))
To filter an array with multiple conditions:Use the && (And) operator to check for multiple conditions. The Array. filter() method will return all elements that satisfy the conditions.
Syntax. The following is the syntax of filter method. Here, p: (A) => Boolean is a predicate or condition to be applied on each element of the list. This method returns the all the elements of list which satisfiles the given condition.
To use filter on your collection, give it a predicate to filter the collection elements as desired. Your predicate should accept a parameter of the same type that the collection holds, evaluate that element, and return true to keep the element in the new collection, or false to filter it out.
Scala filter is a method that is used to select the values in an elements or collection by filtering it with a certain condition.
You could use an implicit class to give you this syntax:
val strs = List("hello", "andorra", "trab", "world")
def f1(s: String) = !s.startsWith("a")
def f2(s: String) = !s.endsWith("b")
val cond1 = true
val cond2 = true
implicit class FilterHelper[A](l: List[A]) {
def ifFilter(cond: Boolean, f: A => Boolean) = {
if (cond) l.filter(f) else l
}
}
strs
.ifFilter(cond1, f1)
.ifFilter(cond2, f2)
res1: List[String] = List(hello, world)
I would have used if
as the method name but it's a reserved word.
You can do this by summing your predicate functions.
Observe that a filter predicate, A => Boolean
, has an append operation:
def append[A](p1: A => Boolean, p2: A => Boolean): A => Boolean =
a => p1(a) && p2(a)
And an identity value:
def id[A]: A => Boolean =
_ => true
which satisfies the condition that for any predicate p: A => Boolean
, append(p, id) === p
.
This simplifies the problem of including/excluding a predicate based on a condition: if the condition is false, simply include the id
predicate. It has no effect on the filter because it always returns true
.
To sum the predicates:
def sum[A](ps: List[A => Boolean]): A => Boolean =
ps.foldLeft[A => Boolean](id)(append)
Note that we fold onto id
, so if ps
is empty, we get the identity predicate, i.e. a filter that does nothing, as you'd expect.
Putting this all together:
val predicates = List(cond1 -> f1 _, cond2 -> f2 _)
strs.filter(sum(predicates.collect { case (cond, p) if cond => p }))
// List(hello, world)
Note that the list strs
was only traversed once.
Now, for the Scalaz version of the above:
val predicates = List(cond1 -> f1 _, cond2 -> f2 _)
strs filter predicates.foldMap {
case (cond, p) => cond ?? (p andThen (_.conjunction))
}
// List("hello", "world")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With