2013-02-14 5 views
45

ちょうど今私はmapValuesが見ることを学ぶことに驚いています。結果は次の例に示します。Scala:なぜmapValuesがビューを生成し、安定した選択肢がありますか?

case class thing(id: Int) 
val rand = new java.util.Random 
val distribution = Map(thing(0) -> 0.5, thing(1) -> 0.5) 
val perturbed = distribution mapValues { _ + 0.1 * rand.nextGaussian } 
val sumProbs = perturbed.map{_._2}.sum 
val newDistribution = perturbed mapValues { _/sumProbs } 

アイデアは、私はそれを再正規化し、いくつかのランダムに摂動さ分布を、持っているということです。このコードは、実際には元の意図で失敗します。mapValuesviewを生成するので、perturbedが使用されるときは常に_ + 0.1 * rand.nextGaussianが再評価されます。

私は現在distribution map { case (s, p) => (s, p + 0.1 * rand.nextGaussian) }のようなことをやっていますが、それは少し冗長です。だからこの質問の目的は:

  1. この事実を知らない人を思い出させます。
  2. なぜ彼らがmapValues出力viewを作る理由を見てください。
  3. コンクリートを生産する別の方法があるかどうかMap
  4. このトラップを持つその他の一般的なコレクションメソッドはありますか。

ありがとうございます。

+1

OMG私は 'mapValues'を使用する別の場所があります。これは時には遅く走る理由です。 – Kane

+1

私もこれに噛まれました。 – ziggystar

+0

今日も私はこの罠に足を踏み入れました。 –

答えて

30

これについてのチケットは、SI-4776(YTによる)です。

するとそれはそれ、これは言って持って紹介するコミット:

jrudolphの提案に続いて、不変 マップの抽象マップ、および重複した機能を変換filterKeysmapValues を作りました。 transformfilterNotを不変のマップから一般的なマップに移動しました。 phallerによるレビュー。

私はjrudolphの元の提案を見つけることができませんでしたが、mapValuesをより効率的にするために行われたと仮定しています。驚きになるかもしれませんが、値を複数回反復する可能性が高い場合は、mapValuesより効率的です。

回避策として、mapValues(...).view.forceを実行して新しいMapを生成することができます。

+4

いいですが、まだ私はmapValuesがそれをより明示的にするために直接ビューを返さないのだろうか? –

+1

@AloisCochardうん、それは良い点です。戻り値の型が 'view'であれば、私たちはそこに起こっていることを警告されるので、もっと良いです。 – Kane

+3

@AloisCochardチケットで見ることができるように、それは私が求めていたものです。 'force'メソッドを直接利用できるようにするというさらなる利点があります。 –

10

Scalaのドキュメントは言う:

f(this(key))に、このマップのすべてのkeyをマップするマップビュー。結果のマップは、要素をコピーせずに元のマップをラップします。

これは予期されるはずですが、これは私に多くの恐怖を与えます。明日のコードを見直す必要があります。私は:-(ただ、他の回避策

のような振る舞いを期待していなかった。

あなたがコピーを入手するためにtoSeqを呼び出すことができ、あなたがtoMapをマッピングするために戻ってそれを必要とするが、この不要なオブジェクトを作成する場合、そして一つは、比較的容易に書き込み、mapValuesビューを作成しない、私は明日それを行うだろうと誰もが私の前にそれを行わない場合は、ここでのコードを投稿することができmap

を使用してオーバーパフォーマンスの意味合いを持っている;)

EDIT:

私はmapValues後に「.MAP(アイデンティティ)」(特定の機能を実装するので、必要はありません)を使用し、「力」ビューに簡単な方法を見つけました:

scala> val xs = Map("a" -> 1, "b" -> 2) 
xs: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1, b -> 2) 

scala> val ys = xs.mapValues(_ + Random.nextInt).map(identity) 
ys: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101) 

scala> ys 
res7: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -> 1315230132, b -> 1614948101) 

それはタイプ残念です返されたのは実際のビューではありません!他の人は「力」と呼ぶことができたでしょう...

+1

がScala '2.12.0-M3'で動作していて、' map(identity) 'があなたに何を買うのかは分かりません:Map(" a " - > 1、" b " - > 2).mapValues(_ + Random .nextInt) 'は' scala.collection.immutable.Map [String、Int] = Map(a - > 1496073565、b - > -1842623900) 'を返します。 詳細を教えてください。私は* mapValuesの潜在的な問題はそれが怠惰に値を評価することだと思っていますが、わかりません。ありがとう –

+0

これは驚くほど驚くべきことです。ビューのマップは、ビューの代わりに具体的なマップをどのように返すことができますか?これは不一致を超えています。これは全く考慮されていません。ソースコードからこのことがまだ2.12に存在することを確認してください。 – HuStmpHrrr

関連する問題