代码之家  ›  专栏  ›  技术社区  ›  Craig P. Motlin

我必须创建一个新对象来混合Scala特性吗?

  •  6
  • Craig P. Motlin  · 技术社区  · 15 年前

    groupBy() 在集合上返回 Map MultiMap . 转换的最简单方法是什么?我可以避免创建新的 多重映射 把所有的东西都复制过来?

    1 回复  |  直到 10 年前
        1
  •  5
  •   Mitch Blevins    15 年前

    我认为“我是否必须创建一个新对象来混合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))
    
    }
    

    补遗

    下面是一个将现有映射[String,Set[Int]]包装到多映射中而不复制值的示例:

    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(…)返回不可变的映射。