Idiomatic Way to Avoid Using a Filter Twice

I’m pretty new to Scala and was writing a toy program to become more comfortable with the language when it occurred to me that there should be a way to reuse the results of a filter without an intermediate val. My dissatisfaction with this approach is that I have to read it out of order.

Is there a better way?

What I started with:

  val avgYrsToRetire =
    people
    .filter(employed)
    .map(yrsToRetire)
    .sum / people.count(employed)

What I hoped for(made up syntax):

  val avgYrsToRetire =
    people
      .filter(employed).scoped { employed =>
      employed.map(yrsToRetire).sum / employed.size
    }

What I ended up with:

  val avgYrsToRetire = ((workers: Seq[Person]) => {
    workers
      .map(yrsToRetire)
      .sum / workers.size
  }) (people.filter(employed))

You can define this scoped operator yourself as follows.

implicit class ScopedSyntax[A](private val a: A) extends AnyVal {
  def scoped[B](f: A => B): B = f(a)
}

Actually this is a pretty well known pattern that many people would like to have in the standard library. Most people call this operator pipe or |>.

2 Likes

Thanks. That lets me write exactly the way I wanted!

You can also use a temporary value to avoid multiple passes over data.

val avgYrsToRetire = {
  val workers = people.filter(employed)
  workers.map(yrsToRetire).sum / workers.size
}
1 Like