Reputation: 4650
I have a Map[String, Int]
val labelMap: mutable.HashMap[String, Int] = sparse0.sparseOperationCountRowsByTarget()
I want to filter that map in one statement. The filter may filter both by String
or Int
In crudest form it looks like this:
val labelMapFiltered = labelMap.filter(label => label._1.startsWith("REL") || label._2 < 400)
Now I already have general utility predicates for String and Int functions. String predicates are:
object StringPredicates
{
def stringEquals(required:String)(input:String) = input == required
def stringStartsWith(required:String)(input:String) = input.startsWith(required)
def stringContains(required:String)(input:String) = input.contains(required)
def and(predicates:Seq[String => Boolean])(input:String) = predicates.forall(predicate => predicate(input))
def or(predicates:Seq[String => Boolean])(input:String) = predicates.exists(predicate => predicate(input))
}
Int predicates are same pattern as above.
This allows for the following filter:
val sw1=stringContains("#")
val sw2=stringStartsWith("REL")
val sw3=intGT(400)
val labelMapFiltered = labelMap.filter( label =>sw1(label._1) || sw2(label._1) || sw3(label._2) )
I want to pass the predicates into the function (as a Seq, I assume) and then filter. So I am looking for something like:
val labelMapFiltered = labelMap.filter( myFunction(myPredSeq))
Can I do this using the predicates I already have? Writing predicates for Tuple2[String,Int]
that match the specific Map in this function seems too specific. I would then have to write predicates for every type of Map I want to filter.
Upvotes: 1
Views: 1212
Reputation: 18424
You can transform your predicates into accepting the appropriate type using the compose
method, e.g.:
val sw1: (String, Int) => Boolean = stringContains("#").compose(kv: (String, Int) => kv._1)
Or even do the same but mapping over your predicates:
val predsOfTuples1 = predsOfStrings.map(_.compose(kv: (String, Int) => kv._1)))
val predsOfTuples2 = predsOfInts.map(_.compose(kv: (String, Int) => kv._2))
val preds = predsOfTuples1 ++ predsOfTuples2
The last thing you would need to do is make your and
and or
methods generic so you can use them on predicates of tuples:
def and[A](predicates:Seq[A => Boolean])(input:A) = predicates.forall(predicate => predicate(input))
def or[A](predicates:Seq[A => Boolean])(input:A) = predicates.exists(predicate => predicate(input))
Upvotes: 5
Reputation: 12794
Let's simplify the input and consider a simple list of Int
s:
List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
You can put all your predicates in a Stream
(so that they're evaluated lazily and you don't have to evaluate all of them):
val predicates = Stream((n: Int) => n == 0, (n: Int) => n % 2 == 1, (n: Int) => n >= 8)
The rules are that numbers will be kept if they are 0, odd or greater or equal to 8.
Now we ask to filter by looking if there is at least one predicate in our collection that returns true
:
list.filter(n => predicates.exists(p => p(n)))
The output is a list of numbers that respect at least one of the rules:
List(0, 1, 3, 5, 7, 8, 9)
Upvotes: 0