Reputation: 1827
I am using some functions that return Options, but I would like to replace them by PartialFunctions in order to use the collect function in Scala. In detail I am trying to call collect (and collectFirst) on a list of objects that contain a partial function in the following way:
class A(val bs : List[B]) {
def getAll(i : Int): List[Int] = bs.map(_.foo(i))
}
class B(val y : Int) {
val foo : PartialFunction[Int, Int] = {
case x if x > y => y
}
}
The above code compiles and does what I want to if the function foo is defined for all values in bs.
val a = new A(List(new B(1), new B(2), new B(3)));
println(a.getAll(5))
prints "List(1, 2, 3)", but of course I run into an error if foo is not defined for a value. Hence, I want to replace it by "collect"
def getAll(i : Int): List[Int] = bs.collect(_.foo(i))
In my understanding collect should work pretty much the same as map, yet still the above code does not compile (I get a type mismatch because foo cannot be resolved). What is the best way in this case?
Upvotes: 0
Views: 194
Reputation: 22374
collect
expects to receive a partial function (not a function or lambda), that will take an element of your collection as an input: PartialFunction[B, Int]
. But here you want just to call your PartialFunction[Int, Int]
inside another function, so you don't even passing a PartialFunction
into collect
(you're passing function (_.foo(i)): B => Int
).
Solution without collect
(but still with PartialFunction
as a member of B
):
def getAll(i : Int): List[Int] = bs.flatMap(_.foo.lift(i))
lift
rises your function from PartialFunction[Int, Int]
to Int => Option[Int]
here.
If you really really want to collect
:
import Function._
def getAll(i : Int): List[Int] = bs.collect(unlift(_.foo.lift(i)))
unlift
reduces B => Option[Int]
into PartialFunction[B, Int]
The ugliest version is collect{ case x if x.foo.isDefinedAt(i) => x.foo(i) }
Better solution is to move your partial function outside of B
:
case class A(bs : List[B]) {
def getAll(x : Int): List[Int] = bs.collect {
case B(y) if x > y => y
}
}
case class B(val y : Int)
Upvotes: 1