Lets say I have a List[TraitA]
of objects. TraitA
provides a property propX : String
.
I know that a subset of this list is also an instance of TraitB
, which however does not provide the property propX
.
So for example:
trait TraitA
{
def propX : String
}
trait TraitB
{
def abc : Int
}
Some of the instances in the list just extend TraitA
, while others extend TraitA with TraitB
. I need to extract only those instances which have TraitB
but I need to retain the property propX
from TraitA
. propX
can only be a few values, and what I need is a Map
which groups the instances of TraitB
according to this value.
So what I need to extract is this subset of TraitB
instances from the List[TraitA]
instances, since some of them are TraitA with TraitB
, and create a Map[String, List[TraitB]]
, where the key is propX
from TraitA
.
I have been fiddling around with for
comprehensions but for some reason I can't yield
a List[(String, TraitB)]
of tuples (which I could then groupBy _.1
), probably because the first generator is of type TraitA
.
I tried this, but it complains that the expected type is List[(String, TraitA)]
:
for {
traitA <- listOfTraitAs
traitBoption = (traitA match {
case traitB : TraitB => Some(traitB)
case _ => None
})
} yield (traitA.propX, traitBoption)
On the other hand, if I filter
the list by pattern matching on TraitB
I lose visibility of propX
in the filtering function.
What is the best approach to achieve this?
I don't see why filter
does not work for you:
scala> trait TraitA { def propX: String }; trait TraitB { def abc: Int }
defined trait TraitA
defined trait TraitB
scala> class A extends TraitA { def propX = util.Random.nextInt(5).toString() }
defined class A
scala> class B extends A with TraitB { def abc = util.Random.nextInt(5) }
defined class B
scala> val xs: List[TraitA] = List.fill(15)(if (util.Random.nextBoolean()) new A else new B)
xs: List[TraitA] = List(A@6b46e91a, B@7c71e0fb, A@1869be91, B@465e2e1c, B@5125545b, A@69c54bfb, B@17ff81fd, A@7af155a, B@77a2cba6, A@60e83ca6, A@2ee5e7fe, B@77e1ecbf, A@117e2d16, A@72c20852, B@20b07a5a)
scala> xs collect { case a: TraitB => a } groupBy (_.propX)
res7: scala.collection.immutable.Map[String,List[TraitA with TraitB]] = Map(4 -> List(B@465e2e1c, B@77e1ecbf), 1 -> List(B@77a2cba6), 0 -> List(B@20b07a5a), 2 -> List(B@7c71e0fb, B@17ff81fd), 3 -> List(B@5125545b))
Even if you loose visibility, you can always do a pattern match with something like { case a: TraitA with TraitB => }
.