Scala のMap
実装のトリッキーな機能に出くわしました。あなたが見逃しているキャッチは、mapValues
実際には new を返さないことですMap
: aview
の a を返しますMap
。つまり、値にアクセスするたびに.toUpperCase
値を返す前に計算するように、元のマップをラップします。
この動作の利点は、Scala がアクセスされていない値の関数を計算せず、すべてのデータを new にコピーするのに時間を費やさないことMap
です。欠点は、その値がアクセスされるたびに関数が再計算されることです。そのため、同じ値に何度もアクセスすると、余分な計算が必要になる場合があります。
では、なぜSortedMap
a を返さないのSortedMap
でしょうか? 実際にはMap
-wrapper を返しているからです。基になる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, U, Repr <: GenTraversable[(T, U)]](self: GenTraversableLike[(T, U), Repr]): EnrichedWithMapVals[T, U, Repr] =
new EnrichedWithMapVals(self)
mapVals
aを呼び出すとSortedMap
、非ビューが返され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,2), ('b,3), ('c,4))