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?
You just need to use the normal option handling methods:
a.map(b.filter).getOrElse(b)
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)
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)
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