I've got a Vector of Vectors that I'm accessing to apply a boolean function. i.e.
Vector[Vector[T]]
where I'm going to execute something along the lines of
f(myVector(i)(j))
where f is of type T => Boolean
.
But this does not do bounds checking, and I can't get something really elegant.
I can use applyOrElse
:
myVector.applyOrElse(i, (_:Int) => Vector.empty).applyOrElse (j, (_:Int) => defaultT)
where f(defaultT)
would return false
But I wish I could just set a default Value instead of a function.
I could use lift to give me an Option
, but it doesn't compose well at the second level:
myVector.lift(i) map (_.lift(j) map f getOrElse false) getOrElse false
Which does work, but is still really hard to read.
And then there's standard if/else blocks:
if (myVector.size <= i) false
else {
val myVector2 = levelVector(i)
if (myVector2.size <= j) false
else f(myVector2(j))
}
It just seems like something that should be able to be decomposed easier than what I can achieve. And if I add a 3rd layer, it's gets even uglier.
Are there other options?
Disclaimer: this is adapted from coursera's progfun course
Take the following code from the question:
myVector.lift(i) map (_.lift(j) map f getOrElse false) getOrElse false
This can be rewritten as follows:
myVector.lift(i).flatMap(_.lift(j)).fold(false)(f)
Or, before fold
was introduced in Scala 2.10:
myVector.lift(i).flatMap(_.lift(j)).map(f).getOrElse(false)
The key idea is to defer unwrapping (or mapping) the Option
for as long as possible. This approach will generalize quite naturally to more than two dimensions.
This is pretty close to equivalent to the for
-comprehension in your answer (assuming you meant to include lift
in there), but once you have to wrap the comprehension in parentheses I personally tend to find the desugared version clearer.
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