51

I would like to filter my data set on two conditions at once.

Is it possible?

I want something like this:

mystuff = mystuff.filter(_.isX && _.name == "xyz")
richsoni
  • 4,188
  • 8
  • 34
  • 47

3 Answers3

81

Using slightly less concise lambda syntax:

mystuff = mystuff.filter(x => (x.isX && x.name == "xyz"))

You can find more detail on Scala anonymous function syntax here.

Alex Wilson
  • 6,690
  • 27
  • 44
  • 1
    does this eliminates the performance overhead? I mean in the end query is this expressed correctly? – zinking Apr 13 '14 at 13:23
10

While there might be some performance impact depending on what "myStuff" is, you could always filter twice

mystuff = mystuff.filter(_.isX).filter(_.name == "xyz")
Dave Griffith
  • 20,435
  • 3
  • 55
  • 76
  • 2
    This causes double looping the whole list. – Kamil Lelonek May 30 '14 at 10:03
  • 5
    @squixy just an FYI, it doesn't. `filter` creates a new projection (or view) of the collection such that when an element is asked for during iteration (i.e. `map`, `fold`, etc...) the `filter` function(s) are applied to see whether the element is returned – ThaDon May 28 '16 at 22:32
  • 1
    @ThaDon not true - it depends on the collection type but the most common (`Array`, `List`, `Vector`...) will create an intermediate collection – Alex Jun 21 '18 at 10:48
6

If you need to frequently filter with several predicate, you could define a way of combining them:

case class And[A]( p1: A=>Boolean, p2: A=>Boolean ) extends (A=>Boolean) {
  def apply( a: A ) = p1(a) && p2(a)
}

Here is how to use it to keep only the odd numbers bigger than 10:

scala> (0 until 20) filter And( _ > 10, _ % 2 == 1 )
res3: scala.collection.immutable.IndexedSeq[Int] = Vector(11, 13, 15, 17, 19)

It easy to write Or and Not combinators in the same fashion.

paradigmatic
  • 40,153
  • 18
  • 88
  • 147
  • 1
    Does this method have an advantage over using a lambda function `mystuff.filter( each => each.isX && each.name.equals("xyz"))` ? – ForeverLearner Feb 05 '20 at 22:11