質問
学習Scala現在、反転に必要な地図に反転価値->キールックアップ私は簡単なこともたけ:
(Map() ++ origMap.map(kvp=>(kvp._2->kvp._1)))
ものであり優雅なアプローチを考えていますか。
解決
と仮定した値は、この作品のユニークされます:
(Map() ++ origMap.map(_.swap))
でのScala 2.8、しかし、それは簡単です:
origMap.map(_.swap)
それを行うことが可能であることはScalaの2.8は、新しいコレクションライブラリを持っている理由の一部です。
他のヒント
数学的には、マッピングがMap[A,B]
から、あなたがMap[B,A]
を得ることができない、例えば、可逆(単射)ではないかもしれませんが、同じ値に関連付けられている異なるキーがある可能性があるためではなく、あなたは、Map[B,Set[A]]
を取得します。だから、あなたはすべてのキーを知ることに興味を持っている場合は、ここでのコードがあります:
scala> val m = Map(1 -> "a", 2 -> "b", 4 -> "b")
scala> m.groupBy(_._2).mapValues(_.keys)
res0: Map[String,Iterable[Int]] = Map(b -> Set(2, 4), a -> Set(1))
あなたは、いくつかの方法で反復しながら._1ものを避けることができます。
ここに1つの方法です。
:これが唯一のケースマップの事項ことをカバー部分関数を使用していますMap() ++ (origMap map {case (k,v) => (v,k)})
ここでもう一つの方法です
import Function.tupled
Map() ++ (origMap map tupled {(k,v) => (v,k)})
マップの繰り返しは2つの要素のタプルを持つ関数を呼び出し、無名関数は、2つのパラメータを望んでいます。 Function.tupledは、翻訳を行います。
私はタイプ地図の地図を反転させる方法を探してここに来た[A、配列[B]]地図に[B、配列[A]、新しいマップ内の各Bは、内のすべてのAに関連付けられている場合BがAの関連配列に含まれたため、古いマップ。
例えば、
Map(1 -> Seq("a", "b"), 2-> Seq("b", "c"))
に反転します
Map("a" -> Seq(1), "b" -> Seq(1, 2), "c" -> Seq(2))
ここに私のソリューションです:
val newMap = oldMap.foldLeft(Map[B, Seq[A]]().withDefaultValue(Seq())) {
case (m, (a, bs)) => bs.foldLeft(m)((map, b) => map.updated(b, m(b) :+ a))
}
oldMapがタイプMap[A, Seq[B]]
であり、NEWMAPのタイプがあるMap[B, Seq[A]]
ネストされたfoldLeftsは、私は少しうんざりしますが、これは、私は反転のこのタイプを達成するために見つけることができる最も簡単な方法です。誰でもクリーンなソリューションがありますか?
OK、これは多くの良い答えを持つ非常に古い質問ですが、私は、これはポストに場所である、スイスアーミーナイフ、Map
インバータオールおよびエンド・オールなると、究極を構築しましたこれます。
それは、実際には2つのインバータです。個々の値の要素の一つ...
//from Map[K,V] to Map[V,Set[K]], traverse the input only once
implicit class MapInverterA[K,V](m :Map[K,V]) {
def invert :Map[V,Set[K]] =
m.foldLeft(Map.empty[V, Set[K]]) {
case (acc,(k, v)) => acc + (v -> (acc.getOrElse(v,Set()) + k))
}
}
...と別の、値のコレクションのために、非常に似ています。
import scala.collection.generic.CanBuildFrom
import scala.collection.mutable.Builder
import scala.language.higherKinds
//from Map[K,C[V]] to Map[V,C[K]], traverse the input only once
implicit class MapInverterB[K,V,C[_]](m :Map[K,C[V]]
)(implicit ev :C[V] => TraversableOnce[V]) {
def invert(implicit bf :CanBuildFrom[Nothing,K,C[K]]) :Map[V,C[K]] =
m.foldLeft(Map.empty[V, Builder[K,C[K]]]) {
case (acc, (k, vs)) =>
vs.foldLeft(acc) {
case (a, v) => a + (v -> (a.getOrElse(v,bf()) += k))
}
}.mapValues(_.result())
}
使用方法:
Map(2 -> Array('g','h'), 5 -> Array('g','y')).invert
//res0: Map(g -> Array(2, 5), h -> Array(2), y -> Array(5))
Map('q' -> 1.1F, 'b' -> 2.1F, 'c' -> 1.1F, 'g' -> 3F).invert
//res1: Map(1.1 -> Set(q, c), 2.1 -> Set(b), 3.0 -> Set(g))
Map(9 -> "this", 8 -> "that", 3 -> "thus", 2 -> "thus").invert
//res2: Map(this -> Set(9), that -> Set(8), thus -> Set(3, 2))
Map(1L -> Iterator(3,2), 5L -> Iterator(7,8,3)).invert
//res3: Map(3 -> Iterator(1, 5), 2 -> Iterator(1), 7 -> Iterator(5), 8 -> Iterator(5))
Map.empty[Unit,Boolean].invert
//res4: Map[Boolean,Set[Unit]] = Map()
私は同じ暗黙のクラスのメソッドが、私はそれが現れたより問題、それに探して費やした多くの時間の両方を持っていることを好むだろう。
あなたが使用してマップを反転できます:
val i = origMap.map({case(k, v) => v -> k})
は、このアプローチの問題は、今、あなたのマップ内のハッシュキーになっているあなたの値は、一意でない場合は、重複した値をドロップしますということです。説明するために:
scala> val m = Map("a" -> 1, "b" -> 2, "c" -> 3, "d" -> 1)
m: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2, c -> 3, d -> 1)
// Notice that 1 -> a is not in our inverted map
scala> val i = m.map({ case(k , v) => v -> k})
i: scala.collection.immutable.Map[Int,String] = Map(1 -> d, 2 -> b, 3 -> c)
はこれを避けるために、あなたが任意の重複する値をドロップしないように、その後、反転、最初のタプルのリストにあなたのマップに変換することができます:
scala> val i = m.toList.map({ case(k , v) => v -> k})
i: List[(Int, String)] = List((1,a), (2,b), (3,c), (1,d))
scala> val m = Map(1 -> "one", 2 -> "two")
m: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one, 2 -> two)
scala> val reversedM = m map { case (k, v) => (v, k) }
reversedM: scala.collection.immutable.Map[java.lang.String,Int] = Map(one -> 1, two -> 2)
重複した値がマップに最後の添加によって上書きされることを注:
scala> val m = Map(1 -> "one", 2 -> "two", 3 -> "one")
m: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> one, 2 -> two, 3 -> one)
scala> val reversedM = m map { case (k, v) => (v, k) }
reversedM: scala.collection.immutable.Map[java.lang.String,Int] = Map(one -> 3, two -> 2)
始 Scala 2.13
, るため、スワップキー/値を失ったキーに関連する価値を利用するとともに、 Map
s新 groupMap 方法、その名のとおり)に相当するものとし groupBy
や map
ping上グループ化。
Map(1 -> "a", 2 -> "b", 4 -> "b").groupMap(_._2)(_._1)
// Map("b" -> List(2, 4), "a" -> List(1))
この:
group
s元素に基づく第二のタプル部_._2
グループの一部 グループ地図)map
sグループ化項目をタプル部_._1
地図のグループ地図)
このとして見ることができ ワンパス版 の map.groupBy(_._2).mapValues(_.map(_._1))
.
逆ですよこの操作により逆に"逆の数理的機能")
私はよくこの逆変換のみならずマップがその他(含む配列番号)。を見たいのでない限の定義を私は逆の操作につ。この定義かの操作のためにマップさながる可能性は私の実施。
def invertMap[A,B]( m: Map[A,B] ) : Map[B,List[A]] = { val k = ( ( m values ) toList ) distinct val v = k map { e => ( ( m keys ) toList ) filter { x => m(x) == e } } ( k zip v ) toMap }
の場合は、一対一のマップ、またシングルトンのリストできるtrivially試験への地図[B]ではなく地図[Bト[A]].
私たちの衝突の世話をして、単一の走査でマップを反転します。このfoldLeft
機能を使用して試すことができます。
scala> def invertMap[A, B](inputMap: Map[A, B]): Map[B, List[A]] = {
| inputMap.foldLeft(Map[B, List[A]]()) {
| case (mapAccumulator, (value, key)) =>
| if (mapAccumulator.contains(key)) {
| mapAccumulator.updated(key, mapAccumulator(key) :+ value)
| } else {
| mapAccumulator.updated(key, List(value))
| }
| }
| }
invertMap: [A, B](inputMap: Map[A,B])Map[B,List[A]]
scala> val map = Map(1 -> 2, 2 -> 2, 3 -> 3, 4 -> 3, 5 -> 5)
map: scala.collection.immutable.Map[Int,Int] = Map(5 -> 5, 1 -> 2, 2 -> 2, 3 -> 3, 4 -> 3)
scala> invertMap(map)
res0: Map[Int,List[Int]] = Map(5 -> List(5), 2 -> List(1, 2), 3 -> List(3, 4))
scala> val map = Map("A" -> "A", "B" -> "A", "C" -> "C", "D" -> "C", "E" -> "E")
map: scala.collection.immutable.Map[String,String] = Map(E -> E, A -> A, B -> A, C -> C, D -> C)
scala> invertMap(map)
res1: Map[String,List[String]] = Map(E -> List(E), A -> List(A, B), C -> List(C, D))