将列表映射到另一个特征的Map的最佳方法

时间:2014-02-15 02:19:14

标签: scala map traits for-comprehension

假设我有List[TraitA]个对象。 TraitA提供了一个属性propX : String。 我知道此列表的一个子集也是TraitB的一个实例,但是它不提供属性propX

例如:

trait TraitA
{
  def propX : String
}

trait TraitB
{
  def abc : Int
}

列表中的部分实例只有extend TraitA,而有些extend TraitA with TraitB。我只需要提取那些TraitB的实例,但我需要保留propX中的属性TraitApropX只能是一些值,而我需要的是Map,它根据此值对TraitB的实例进行分组。

所以我需要提取的是来自TraitB个实例的List[TraitA]个实例的子集,因为其中一些实例是TraitA with TraitB,并创建了一个Map[String, List[TraitB]],其中密钥是来自propX的{​​{1}}。

我一直在摆弄TraitA理解但由于某种原因,我不能for yield元组(我可以List[(String, TraitB)]),可能是因为第一个生成器是groupBy _.1类型。

我试过这个,但它抱怨预期的类型是TraitA

List[(String, TraitA)]

另一方面,如果我for { traitA <- listOfTraitAs traitBoption = (traitA match { case traitB : TraitB => Some(traitB) case _ => None }) } yield (traitA.propX, traitBoption) filter上的模式匹配列表,我会在过滤功能中失去TraitB的可见性。

实现这一目标的最佳方法是什么?

1 个答案:

答案 0 :(得分:2)

我不明白为什么filter不适合你:

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))

即使您失去了可见性,也可以使用{ case a: TraitA with TraitB => }等方式进行模式匹配。