変更可能なマップを使用して発生/カウントを追跡するという単純な問題を考えてみましょう。つまり、次のようになります。
val counts = collection.mutable.Map[SomeKeyType, Int]()
カウントをインクリメントするための私の現在のアプローチは次のとおりです。
counts(key) = counts.getOrElse(key, 0) + 1
// or equivalently
counts.update(key, counts.getOrElse(key, 0) + 1)
キーを 2 回指定する必要があるため、これは少しぎこちなく感じます。パフォーマンスに関してはkey
、マップ内で 2 回配置する必要があることも予想されますが、これは避けたいと思います。興味深いことに、このアクセスと更新の問題はInt
、それ自体を変更するメカニズムを提供する場合には発生しません。Int
関数を提供するCounter
クラスに変更するincrement
と、たとえば次のことが可能になります。
// not possible with Int
counts.getOrElseUpdate(key, 0) += 1
// but with a modifiable counter
counts.getOrElseUpdate(key, new Counter).increment
どういうわけか、可変マップを使用して次の機能を備えていることを常に期待しています(多少似てtransform
いますが、新しいコレクションを返さず、デフォルト値を持つ特定のキーに基づいています):
// fictitious use
counts.updateOrElse(key, 0, _ + 1)
// or alternatively
counts.getOrElseUpdate(key, 0).modify(_ + 1)
しかし、私が見る限り、そのような機能は存在しません。f: A => A
そのようなインプレース変更の可能性を持つことは、一般的に (パフォーマンスと構文に関して) 理にかなっているのではないでしょうか? おそらく私はここで何かが欠けているだけです...この問題には、そのような機能を不要にするより良い解決策があるに違いないと思いますか?
アップデート:
私が認識していることを明確にする必要がありましたが、問題は同じままです。O (1) 操作であるかどうかに関係なく、withDefaultValue
2 つのルックアップを実行すると、1 回よりも2 倍遅くなります。率直に言って、多くの状況で 2 倍のスピードアップを達成できれば幸いです。また、変更クロージャの構築はループの外に移動できることが多いため、これは、無駄な操作を2回。