Ore*_*ren 11 scala map treemap sortedmap
我是Scala的新手.我在我的代码中使用了SortedMap,我想使用mapValues创建一个新的地图,并对值进行一些转换.
mapValues函数返回一个新的Map,而不是返回一个新的SortedMap,然后我必须将其转换为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:_ *)
Run Code Online (Sandbox Code Playgroud)
这看起来效率低下 - 最后一次转换可能会再次对键进行排序,或者至少验证它们是否已排序.
我可以使用普通的map函数,它既可以对键和值进行操作,也可以故意不改变转换函数中的键.这看起来太低效,因为执行地图可能假设转换可以(在的情况下,如:改变键的顺序my_map.map(tup => (-tup._1, tup._2)) -所以它可能"重新排序"他们.
有人熟悉Map和SortedMap的内部实现,可以告诉我我的假设是否正确吗?编译器能否自动识别出密钥没有重新排序?是否有内部原因导致mapValues不应返回SortedMap?有没有更好的方法来转换地图的值而不会失去键的顺序?
谢谢
dhg*_*dhg 16
你偶然发现了Scala Map实现的一个棘手的功能.你缺少的是它mapValues实际上并没有返回一个新的Map:它返回一个viewa Map.换句话说,它以这样的方式包装原始地图:无论何时访问某个值,它都会.toUpperCase在将值返回给您之前进行计算.
这种行为的好处是Scala不会为未访问的值计算函数,也不会花时间将所有数据复制到新的数据中Map.缺点是每次访问该值时都会重新计算该函数.因此,如果多次访问相同的值,最终可能会进行额外的计算.
那么为什么不SortedMap归还SortedMap?因为它实际上正在返回一个Map包装器.底层的Map,然后是一个被包装的,仍然是一个SortedMap,所以如果你要迭代,它仍然是按排序顺序.你和我都知道,但是类型检查器没有.看起来他们似乎可以用这样的方式写它,它仍然保持着SortedMap特性,但他们没有.
您可以在代码中看到它没有返回a 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))
...
Run Code Online (Sandbox Code Playgroud)
解决问题的方法与解决视图问题的解决方案相同:.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, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]): EnrichedWithMapVals[T, U, Repr] =
new EnrichedWithMapVals(self)
Run Code Online (Sandbox Code Playgroud)
现在,当你打电话mapVals给SortedMap你时,你会得到一个非视图SortedMap:
scala> val m3 = m1.mapVals(_ + 1)
m3: SortedMap[String,Int] = Map(aardvark -> 2, cow -> 6, dog -> 10)
Run Code Online (Sandbox Code Playgroud)
它实际上适用于任何对的集合,而不仅仅是Map实现:
scala> List(('a,1),('b,2),('c,3)).mapVals(_+1)
res8: List[(Symbol, Int)] = List(('a,2), ('b,3), ('c,4))
Run Code Online (Sandbox Code Playgroud)