我是否必须创建一个新的对象以混合Scala特征?

时间:2009-11-27 19:19:33

标签: scala traits

在Scala中,对集合调用groupBy()会返回Map,其中值为集合,但我想要MultiMap。什么是最简单的转换方式?我可以避免创建新的MultiMap并复制一切吗?

1 个答案:

答案 0 :(得分:5)

我认为答案是“我是否必须创建一个新的对象以混合Scala特征?”是是的”。你可以通过包装对象和隐式转换来减少一些痛苦。


对于您的具体问题,我无法强制groupBy(...)将可变映射返回到可变集,您需要使用“MapProxy with MultiMap”将其包装。但是,实现您自己的“groupBy”版本并不是太多代码:

package blevins.example

object App extends Application {

  implicit def multiMapable[B](c: Iterable[B]) = new {
    def groupByMM[A](f: B => A) = {
      import scala.collection.mutable._
      val ret = new HashMap[A,Set[B]] with MultiMap[A,B]
      for (e <- c) { ret.addBinding(f(e), e) }
      ret
    } 
  }

  val c = List(1,2,3,4,5,6,7,8,9)
  val mm = c.groupByMM { i => if (i < 5) "alpha" else "beta" }
  mm.addBinding("alpha",12)
  println(mm) // Map(beta -> Set(5, 7, 6, 9, 8), alpha -> Set(3, 1, 4, 2, 12))

}

<强>附录

以下是将现有Map [String,Set [Int]]包装到MultiMap中而不​​复制值的示例:

object App extends Application {
  import scala.collection.mutable._
  val seed: Map[String,Set[Int]] = Map("even" -> Set(2,4,6), "odd" -> Set(1,3,5))

  val multiMap = new MapProxy[String,Set[Int]] with MultiMap[String,Int] {
    val self = seed
  }

  multiMap.addBinding("even", 8)
  println(multiMap) // Map(odd -> Set(5, 3, 1), even -> Set(6, 8, 4, 2))
}

请注意,无法对groupBy(...)的结果进行此操作,因为种子映射必须是可变的,并且groupBy(...)返回不可变映射。