Scala:为什么SortedMap的mapValues返回Map而不是SortedMap?
我是
Scala新手.
我在我的代码中使用了 SortedMap,我想使用mapValues来创建一个新的地图,并对这些值进行一些转换. 而不是返回一个新的SortedMap,mapValues函数返回一个新的Map,然后我必须转换为SortedMap. 例如 val my_map = SortedMap(1 -> "one",0 -> "zero",2 -> "two") val new_map = my_map.mapValues(name => name.toUpperCase) // returns scala.collection.immutable.Map[Int,java.lang.String] = Map(0 -> ZERO,1 -> ONE,2 -> TWO) val sorted_new_map = SortedMap(new_map.toArray:_ *) 这看起来效率不高 – 最后的转换可能会再次分配密钥,或者至少验证它们是否被排序. 我可以使用在键和值上操作的法线贴图功能,并且故意不改变我的转换功能中的键.这看起来效率不高,因为Map的实现可能假设转换可能会改变键的顺序(就像在这样的情况:my_map.map(tup =>(-tup._1,tup._2))),所以它他们也可能“重新排序”他们. 有人熟悉Map和SortedMap的内部实现,可以告诉我我的假设是否正确?编译器能否自动识别钥匙是否未重新排序?为什么mapValues不应该返回SortedMap是否有内部原因?有没有更好的方式来转换地图的值而不会失去键的顺序? 谢谢 解决方法
您偶然发现了Scala的地图实施的棘手功能.你缺少的catch是mapValues实际上并没有返回一个新的Map:它返回一个Map的视图.换句话说,它包装你的原始地图,只要你访问一个值,它将计算.toUpperCase,然后返回值.
这种行为的优点是Scala不会计算未被访问的值的函数,并且不会花费时间将所有数据复制到新的Map中.缺点是每次访问该值时都会重新计算该函数.因此,如果您访问相同的值多次,您可能会最终进行额外的计算. 那么为什么SortedMap不返回SortedMap?因为它实际上是返回一个Map-wrapper.底层的Map,然后是一个被包装的Map,仍然是一个SortedMap,所以如果你要迭代,它仍然是排序顺序.你和我知道,但类型检查没有.看起来好像他们可以写这样一种方式,它仍然保持SortedMap特性,但是没有. 您可以在代码中看到它没有返回SortedMap,但是迭代行为仍将被排序: // from MapLike override def mapValues[C](f: B => C): Map[A,C] = new DefaultMap[A,C] { def iterator = for ((k,v) <- self.iterator) yield (k,f(v)) ... 解决问题的方法与解决视图问题的方法相同:使用.map {case(k,v)=> (k,f(v))},如你在你的问题中提到的. 如果你真的想要那种方便的方法,你可以做我所做的,并写你自己,更好的版本的mapValues: class EnrichedWithMapVals[T,U,Repr <: GenTraversable[(T,U)]](self: GenTraversableLike[(T,U),Repr]) { /** * In a collection of pairs,map a function over the second item of each * pair. Ensures that the map is computed at call-time,and not returned * as a view as 'Map.mapValues' would do. * * @param f function to map over the second item of each pair * @return a collection of pairs */ def mapVals[R,That](f: U => R)(implicit bf: CanBuildFrom[Repr,(T,R),That]) = { val b = bf(self.asInstanceOf[Repr]) b.sizeHint(self.size) for ((k,v) <- self) b += k -> f(v) b.result } } implicit def enrichWithMapVals[T,Repr]): EnrichedWithMapVals[T,Repr] = new EnrichedWithMapVals(self) 现在,当您在SortedMap上调用mapVals时,您将返回一个非查看SortedMap: scala> val m3 = m1.mapVals(_ + 1) m3: SortedMap[String,Int] = Map(aardvark -> 2,cow -> 6,dog -> 10) 它实际上适用于任何对的集合,而不仅仅是Map实现: scala> List(('a,1),('b,2),('c,3)).mapVals(_+1) res8: List[(Symbol,Int)] = List(('a,3),4)) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |