Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditionally filter a sequence

Tags:

scala

Suppose I have an Option[A => Boolean], a List[A], and some set of operations I want to perform on a subset of that list. If the option is set, then I want to filter the list first and then apply my operations. If not, then I want to apply it on the whole list. An example:

val a : Option[Int => Boolean] = Option((a : Int) => a % 2 == 0)
val b = 1 to 100

I can easily do the following:

val c = if (a.isDefined) b.filter(a.get) else b

However, this involves calling a.get; much conditioning leaves me unable to do this! I could alternatively do:

val c = b.filter(a.getOrElse(_ => true))

This feels better, but now I am stuck with a second (albeit trivial) operation being carried out for every element of my sequence. I could hope that it will be optimised out, but this still feels imperfect.

What I would like is something lacking either flaw. It feels like there should be a nice way to do it - any ideas?

like image 766
Submonoid Avatar asked Feb 07 '12 17:02

Submonoid


3 Answers

You just need to use the normal option handling methods:

a.map(b.filter).getOrElse(b)
like image 163
Rex Kerr Avatar answered Sep 21 '22 02:09

Rex Kerr


Basically same as Rex Kerr's solution, but uses fold from Scalaz to make it slightly more concise.

In general, x.fold(f, g)x.map(f).getOrElse(g).

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> a.fold(b.filter, b)
res112: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100)
like image 24
missingfaktor Avatar answered Sep 24 '22 02:09

missingfaktor


How about changing a to:

val a : Option[Seq[Int] => Seq[Int]] = Option((a : Seq[Int]) => a.filter(_ % 2 == 0))
val b = 1 to 100
val c = a.getOrElse((f:Seq[Int]) => f)(b)

(Note I haven't tried the above, but it should give you the idea)

like image 25
Chris Shain Avatar answered Sep 25 '22 02:09

Chris Shain