Scala:どのように統合集の地図
-
13-09-2019 - |
質問
いリスト地図[文字列をダブル]ていただきたいと思いますように合併その内容を単一の地図[文字列をダブル].どうすればよいことには慣用的。ってきたのでしょうか私はできるということ折りにします。のようなもの:
val newMap = Map[String, Double]() /: listOfMaps { (accumulator, m) => ... }
さらに、そういったポジションになります。衝突に一般的です。る場合、Iキーの追加を図ることが既に存在していることができる指定することができる機能を返しまダブル(この場合)か、既存の価値そのキーの値ようにしています。そのキーがまだ存在していないの地図は、キャラクター設定を追加することの価値わ.
私の特定の場合にはんを一枚の地図[文字列をダブル]なした場合には、地図がすでに含まれているキーのダブルに追加する既存の地図。
私と変更可能な地図は私の特定のコードがに興味がある私にとってより汎用ソリューション、場合に可能です。
解決
どの程度、この1:
def mergeMap[A, B](ms: List[Map[A, B]])(f: (B, B) => B): Map[A, B] =
(Map[A, B]() /: (for (m <- ms; kv <- m) yield kv)) { (a, kv) =>
a + (if (a.contains(kv._1)) kv._1 -> f(a(kv._1), kv._2) else kv)
}
val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
val mm = mergeMap(ms)((v1, v2) => v1 + v2)
println(mm) // prints Map(hello -> 5.5, world -> 2.2, goodbye -> 3.3)
そして、それは2.7.5と2.8.0の両方で動作します。
他のヒント
さて、あなたが行うことができます:
mapList reduce (_ ++ _)
衝突のための特別な要件を除きます。
あなたがその特別な要件を持っているので、おそらく最高のは、このような何か(2.8)をやっなります:
def combine(m1: Map, m2: Map): Map = {
val k1 = Set(m1.keysIterator.toList: _*)
val k2 = Set(m2.keysIterator.toList: _*)
val intersection = k1 & k2
val r1 = for(key <- intersection) yield (key -> (m1(key) + m2(key)))
val r2 = m1.filterKeys(!intersection.contains(_)) ++ m2.filterKeys(!intersection.contains(_))
r2 ++ r1
}
あなたはその後、ポン引きマイライブラリパターンを介してマップクラスにこのメソッドを追加し、代わりに「++
」の元の例では、それを使用することができます:
class CombiningMap(m1: Map[Symbol, Double]) {
def combine(m2: Map[Symbol, Double]) = {
val k1 = Set(m1.keysIterator.toList: _*)
val k2 = Set(m2.keysIterator.toList: _*)
val intersection = k1 & k2
val r1 = for(key <- intersection) yield (key -> (m1(key) + m2(key)))
val r2 = m1.filterKeys(!intersection.contains(_)) ++ m2.filterKeys(!intersection.contains(_))
r2 ++ r1
}
}
// Then use this:
implicit def toCombining(m: Map[Symbol, Double]) = new CombiningMap(m)
// And finish with:
mapList reduce (_ combine _)
これは2.8で書かれ、そのkeysIterator
は2.7 keys
になりましたが、、filterKeys
はfilter
がmap
なり、&
と**
の項で記述される必要があるかもしれません、というように、それはあまりにも異なることはないはずです。
だと思いますが、良いモノをつくこのソリューションを使って
myListOfMaps.flatten.toMap
など必要なもの:
- 合併のリストを一枚の地図
- 雑草の合鍵
例:
scala> List(Map('a -> 1), Map('b -> 2), Map('c -> 3), Map('a -> 4, 'b -> 5)).flatten.toMap
res7: scala.collection.immutable.Map[Symbol,Int] = Map('a -> 4, 'b -> 5, 'c -> 3)
flatten
回を重ねるごとにリストのマップを平のリストタプル, toMap
また、部品点数の少なリストタプルへの地図の複製キーの削除
私は何かが欠けていた場合、私はわからないので、すぐにこの質問を読んで(それが2.7.35または全くscalazのために働くために持っているよう):
import scalaz._
import Scalaz._
val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
ms.reduceLeft(_ |+| _)
// returns Map(goodbye -> 3.3, hello -> 5.5, world -> 2.2)
あなたは最大を取得し、ここで、二重のためのモノイドの定義を変更し、値を蓄積する別の方法を取得することができます:
implicit val dbsg: Semigroup[Double] = semigroup((a,b) => math.max(a,b))
ms.reduceLeft(_ |+| _)
// returns Map(goodbye -> 3.3, hello -> 4.4, world -> 2.2)
興味深い、このビットの周りヌードリング、私が得た(2.7.5で)次:
一般地図ます:
def mergeMaps[A,B](collisionFunc: (B,B) => B)(listOfMaps: Seq[scala.collection.Map[A,B]]): Map[A, B] = {
listOfMaps.foldLeft(Map[A, B]()) { (m, s) =>
Map(
s.projection.map { pair =>
if (m contains pair._1)
(pair._1, collisionFunc(m(pair._1), pair._2))
else
pair
}.force.toList:_*)
}
}
投影と強制とToListメソッドとその他もろもろと恐ろしいであるしかし、人、。個別の質問:倍以内それに対処するための良い方法は何でしょう。
?私は私のコードで扱った、そしてあまり一般的な解決策で、私はこれを得たものである可変地図については、
def mergeMaps[A,B](collisionFunc: (B,B) => B)(listOfMaps: List[mutable.Map[A,B]]): mutable.Map[A, B] = {
listOfMaps.foldLeft(mutable.Map[A,B]()) {
(m, s) =>
for (k <- s.keys) {
if (m contains k)
m(k) = collisionFunc(m(k), s(k))
else
m(k) = s(k)
}
m
}
}
少しクリーナーようだが、それが書かれているようにのみ変更可能な地図で動作すること。代わりにfoldLeftのが、私は型エラーを得ていた。興味深いことに、(私は質問をする前に)私が最初に/使用して上記を試してみました。私は/考えた:とfoldLeftは基本的に同等であったが、コンパイラは、私は(M、S)の明示的な型が必要だと訴えて続けました。どうなっているのですか?
、それをチェックアウトします:
http://www.nimrodstech.com/scala-map-merge/
基本的にscalaz半グループを使用して、あなたはこれを達成することができ、かなり簡単に
のようになります:
import scalaz.Scalaz._
listOfMaps reduce(_ |+| _)
始 Scala 2.13
, 他のソリューション 鍵の取り扱 みや に基づく標準ライブラリ さらにその合併に Map
sとして配列(flatten
用前に新 groupMapReduce オペレーター(その名のとおり)に相当するものとし groupBy
続いてマッピングおよび削減のステップグループ化された値:
List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
.flatten
.groupMapReduce(_._1)(_._2)(_ + _)
// Map("world" -> 2.2, "goodbye" -> 3.3, "hello" -> 5.5)
この:
flatten
s(concatenates)の地図として配列のタプル(List(("hello", 1.1), ("world", 2.2), ("goodbye", 3.3), ("hello", 4.4))
るすべてのキーと値のペアをも複製キー)group
s元素に基づく最初のタプル部_._1
グループの一部 グループMapReduce)map
sグループ化の価値を第二のタプル部_._2
地図のグループ地図削減)reduce
s"マグ値_+_
)によるその和ができreduce: (T, T) => T
機能(低減のgroupMap削減)
の groupMapReduce
ステップとして見ることができ ワンパス版 相当のもの
list.groupBy(_._1).mapValues(_.map(_._2).reduce(_ + _))
その用法scalazを使用するのとほとんど同じくらいきれい読み込みonelinerヘルパー-FUNC、ます:
def mergeMaps[K,V](m1: Map[K,V], m2: Map[K,V])(f: (V,V) => V): Map[K,V] =
(m1 -- m2.keySet) ++ (m2 -- m1.keySet) ++ (for (k <- m1.keySet & m2.keySet) yield { k -> f(m1(k), m2(k)) })
val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
ms.reduceLeft(mergeMaps(_,_)(_ + _))
// returns Map(goodbye -> 3.3, hello -> 5.5, world -> 2.2)
究極の可読性のために暗黙のカスタム型でそれをラップします:
class MyMap[K,V](m1: Map[K,V]) {
def merge(m2: Map[K,V])(f: (V,V) => V) =
(m1 -- m2.keySet) ++ (m2 -- m1.keySet) ++ (for (k <- m1.keySet & m2.keySet) yield { k -> f(m1(k), m2(k)) })
}
implicit def toMyMap[K,V](m: Map[K,V]) = new MyMap(m)
val ms = List(Map("hello" -> 1.1, "world" -> 2.2), Map("goodbye" -> 3.3, "hello" -> 4.4))
ms reduceLeft { _.merge(_)(_ + _) }