val map1 = Map(1 -> 9 , 2 -> 20)
val map2 = Map(1 -> 100, 3 -> 300)
それらをマージして、同じキーの値を合計したいと思います。したがって、結果は次のようになります。
Map(2->20, 1->109, 3->300)
今私は2つの解決策を持っています:
val list = map1.toList ++ map2.toList
val merged = list.groupBy ( _._1) .map { case (k,v) => k -> v.map(_._2).sum }
そして
val merged = (map1 /: map2) { case (map, (k,v)) =>
map + ( k -> (v + map.getOrElse(k, 0)) )
}
しかし、もっと良い解決策があるかどうか知りたいです。
Scalazは、という概念がある半群、あなたがここで何をしたいのかキャプチャし、そして間違いなく最短/きれいな解決策につながります:
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val map1 = Map(1 -> 9 , 2 -> 20)
map1: scala.collection.immutable.Map[Int,Int] = Map(1 -> 9, 2 -> 20)
scala> val map2 = Map(1 -> 100, 3 -> 300)
map2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 100, 3 -> 300)
scala> map1 |+| map2
res2: scala.collection.immutable.Map[Int,Int] = Map(1 -> 109, 3 -> 300, 2 -> 20)
具体的には、の二項演算子Map[K, V]
はマップのキーを結合し、V
重複する値に対しての半群演算子を折りたたみます。の標準セミグループInt
は加算演算子を使用するため、重複する各キーの値の合計を取得します。
編集:user482745の要求に従って、もう少し詳細。
数学的には、半群は、そのセットから2つの値を取得し、そのセットから別の値を生成する演算子を含む、単なる値のセットです。したがって、加算中の整数は半群です。たとえば、+
演算子は2つのintを組み合わせて別のintを作成します。
2つのマップを組み合わせて、何らかの形で2つのマップを組み合わせた新しいマップを作成する操作を考え出すことができる限り、「特定のキータイプと値タイプを持つすべてのマップ」のセットに対して半群を定義することもできます。入力。
両方のマップに表示されるキーがない場合、これは簡単です。両方のマップに同じキーが存在する場合は、キーがマップされる2つの値を組み合わせる必要があります。うーん、同じタイプの2つのエンティティを組み合わせる演算子について説明しただけではありませんか?これがMap[K, V]
、Scalazで、の半群が存在する場合にのみ、の半群がV
存在する理由です-V
の半群は、同じキーに割り当てられた2つのマップからの値を組み合わせるために使用されます。
ここでInt
は値型であるため、1
キーの「衝突」は、2つのマップされた値の整数加算によって解決されます(これは、Intの半群演算子が行うことです)100 + 9
。したがって、。値が文字列であった場合、衝突により、2つのマップされた値の文字列が連結されます(これも、Stringのセミグループ演算子が行うためです)。
(そして興味深いことに、文字列の連結は可換ではないため、つまり"a" + "b" != "b" + "a"
、結果の半群演算も可換ではありません。したがって、Stringの場合とmap1 |+| map2
は異なりますmap2 |+| map1
が、Intの場合とは異なります。)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加