Reputation: 1584
I have a class structure like this
abstract class A
class B extends A
class C extends A
class D extends A
class E extends A
and I have a collection of the various instances, for example:
val xs = List(new D, new B, new E, new E, new C, new B)
My question is, is there an elegant way to filter out some of the subclasses from the List?
Let's say I want all instances except B's and C's. I can do it with a bunch of isInstanceOf's, or using collect like this:
val ys = (xs collect {
case b: B => None
case c: C => None
case notBorC => notBorC
}).filter(_ != None).asInstanceOf[List[A]]
This works but it feels awkward, mostly because of the filter and cast. Is there a more elegant way? Less code is preferred, and I'd like to have a solution that doesn't need to be updated if I add more subclasses of A.
Upvotes: 58
Views: 21591
Reputation: 8425
collect
can be used to filter values on which the function is defined:
Get all values of type A:
xs.collect { case a: A => a }
Get all values except B and C:
xs diff xs.collect { case x@(_: B | _: C) => x }
Upvotes: 112
Reputation: 139028
flatMap
that shit! (as they say):
scala> val ys = xs flatMap {
| case _: B | _: C => None
| case other => Some(other)
| }
ys: List[A] = List(D@7ecdc97b, E@2ce07e6b, E@468bb9d1)
In your case you were getting a List[ScalaObject]
because ScalaObject
is the least upper bound of None
, D
, and E
.
Upvotes: 55
Reputation: 1584
Formulating problems as questions seems to be a pretty good way of solving them :) My question actually provides the answer - just filter by subtype:
val ys = xs filterNot(List(classOf[B], classOf[C]) contains _.getClass)
Upvotes: 4