web-dev-qa-db-ja.com

mapValuesとMapの変換の違い

In Scala Map[〜#〜] api [〜#〜] を参照)what mapValuestransformのセマンティクスとパフォーマンスの違いは何ですか?

たとえば、特定のマップについて

val m = Map( "a" -> 2, "b" -> 3 )

どちらも

m.mapValues(_ * 5)
m.transform( (k,v) => v * 5 )

同じ結果をもたらします。

23
elm

_Map[A,B]_があるとします。明確にするために:私は常に不変のMapを参照しています。

mapValuesは、関数_B => C_を取ります。ここで、Cは値の新しい型です。

transformは関数_(A, B) => C_を取ります。このCは値の型でもあります。

したがって、両方とも_Map[A,C]_になります。

ただし、transform関数を使用すると、キーの値によって新しい値の結果に影響を与えることができます。

例えば:

_val m = Map( "a" -> 2, "b" -> 3 )
m.transform((key, value) => key + value) //Map[String, String](a -> a2, b -> b3)
_

mapValuesでこれを行うのは非常に困難です。

次の違いは、transformが厳密であるのに対し、mapValuesはビューのみを提供し、更新された要素を保存しないことです。次のようになります。

_protected class MappedValues[C](f: B => C) extends AbstractMap[A, C] with DefaultMap[A, C] {
  override def foreach[D](g: ((A, C)) => D): Unit = for ((k, v) <- self) g((k, f(v)))
  def iterator = for ((k, v) <- self.iterator) yield (k, f(v))
  override def size = self.size
  override def contains(key: A) = self.contains(key)
  def get(key: A) = self.get(key).map(f)
}
_

https://github.com/scala/scala/blob/v2.11.2/src/library/scala/collection/MapLike.scala#L244 から取得)

したがって、パフォーマンス面では、より効果的なものに依存します。 fが高価で、結果のマップのいくつかの要素のみにアクセスする場合、mapValuesはオンデマンドでのみ適用されるため、fの方が適している場合があります。そうでなければ、mapまたはtransformに固執します。

transformは、mapでも表現できます。 _m: Map[A,B]_およびf: (A,B) => Cを想定してから、

m.transform(f)m.map{case (a, b) => (a, f(a, b))}と同等です

42
Kigyo

collection.Maptransformを提供しません:可変マップと不変マップに対して異なるシグネチャを持っています。

$ scala
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val im = Map('a -> 1, 'b -> 2, 'c -> 3)
im: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 1, 'b -> 2, 'c -> 3)

scala> im.mapValues(_ * 7) eq im
res0: Boolean = false

scala> im.transform { case (k,v) => v*7 } eq im
res2: Boolean = false

scala> val mm = collection.mutable.Map('a -> 1, 'b -> 2, 'c -> 3)
mm: scala.collection.mutable.Map[Symbol,Int] = Map('b -> 2, 'a -> 1, 'c -> 3)

scala> mm.mapValues(_ * 7) eq mm
res3: Boolean = false

scala> mm.transform { case (k,v) => v*7 } eq mm
res5: Boolean = true

可変変換は所定の場所で変異します:

scala> mm.transform { case (k,v) => v*7 }
res6: mm.type = Map('b -> 98, 'a -> 49, 'c -> 147)

scala> mm.transform { case (k,v) => v*7 }
res7: mm.type = Map('b -> 686, 'a -> 343, 'c -> 1029)

したがって、可変変換はマップのタイプを変更しません。

scala> im mapValues (_ => "hi")
res12: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)

scala> mm mapValues (_ => "hi")
res13: scala.collection.Map[Symbol,String] = Map('b -> hi, 'a -> hi, 'c -> hi)

scala> mm.transform { case (k,v) => "hi" }
<console>:9: error: type mismatch;
 found   : String("hi")
 required: Int
              mm.transform { case (k,v) => "hi" }
                                           ^

scala> im.transform { case (k,v) => "hi" }
res15: scala.collection.immutable.Map[Symbol,String] = Map('a -> hi, 'b -> hi, 'c -> hi)

...新しいマップを作成するときに起こりうることです。

9
som-snytt

言及されていない違いがいくつかあります。

  • mapValuesは、それが単なるビューであることを示すことなく、シリアル化できないマップを作成します(タイプはMap[_, _]、ただし、ネットワーク経由で送信してみてください)。

  • mapValuesは単なるビューであるため、すべてのインスタンスには実際のMap-mapValuesの別の結果である可能性がありますが含まれます。ある状態のアクターがあり、状態が変化するたびに新しい状態が前の状態のmapValuesに設定されると想像してください。俳優の(そして、はい、これらの両方は経験からです)。

7
codingismy11to7