जवाबों:
मान लेना अद्वितीय है, यह काम करता है:
(Map() ++ origMap.map(_.swap))
स्कैला 2.8 पर, हालांकि, यह आसान है:
origMap.map(_.swap)
ऐसा करने में सक्षम होने के कारण स्काला 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))
.map(_._1)
अधिक लेगीबाइल के रूप में होगा.keys
Set
की तरह List
एस के बजाय एस हो जाते हैं।
.mapValues
क्योंकि यह एक दृश्य लौटाता है। कभी-कभी, यह वही है जो आप चाहते हैं, लेकिन अगर आप सावधान नहीं हैं तो यह बहुत सारी मेमोरी और सीपीयू का उपभोग कर सकता है। यह एक नक्शे में बाध्य करने के लिए, आप कर सकते हैं m.groupBy(_._2).mapVaues(_.keys).map(identity)
, या आप के लिए कॉल की जगह सकता है .mapValues(_.keys)
के साथ .map { case (k, v) => k -> v.keys }
।
कुछ तरीकों से पुनरावृत्ति करते हुए आप ._1 सामग्री से बच सकते हैं।
यहाँ एक तरीका है। यह एक आंशिक फ़ंक्शन का उपयोग करता है जो नक्शे के लिए एक और एकमात्र मामले को कवर करता है:
Map() ++ (origMap map {case (k,v) => (v,k)})
यहाँ एक और तरीका है:
import Function.tupled
Map() ++ (origMap map tupled {(k,v) => (v,k)})
नक्शा पुनरावृत्ति एक फ़ंक्शन को दो तत्व टपल के साथ कहता है, और अनाम फ़ंक्शन दो पैरामीटर चाहता है। Function.tupled अनुवाद बनाता है।
मैं यहां एक नक्शा प्रकार के नक्शे [A, Seq [B]] को Map [B, Seq [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))
}
जहां पुराना नक्शा प्रकार Map[A, Seq[B]]
का होता है और नया नक्शा प्रकार का होता हैMap[B, Seq[A]]
नेस्टेड फोल्डफेट्स ने मुझे थोड़ा सा तंग कर दिया है, लेकिन यह सबसे सीधा तरीका है जो मुझे इस प्रकार के व्युत्क्रम को पूरा करने के लिए मिल सकता है। किसी के पास एक क्लीनर समाधान है?
Map[A, Seq[B]]
करने के लिए Map[B, Seq[A]]
जहां अपने समाधान trasnforms Map[A, Seq[B]]
लिए Map[Seq[B], Seq[A]]
।
a.toSeq.flatMap { case (a, b) => b.map(_ -> a) }.groupBy(_._2).mapValues(_.map(_._1))
ठीक है, इसलिए यह कई अच्छे उत्तरों के साथ एक बहुत पुराना सवाल है, लेकिन मैंने अंतिम, सभी-और-अंत-सभी, स्विस-आर्मी-चाकू, Map
इन्वर्टर का निर्माण किया है और यह इसे पोस्ट करने का स्थान है।
यह वास्तव में दो इनवर्टर है। व्यक्तिगत मूल्य तत्वों के लिए एक ...
//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 REPL में:
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
नई GroupMap पद्धति का उपयोग कर सकते हैं , जो (जैसा कि इसके नाम से पता चलता है) समूहीकृत groupBy
और map
समूहित वस्तुओं पर एक पिंग के बराबर है ।
Map(1 -> "a", 2 -> "b", 4 -> "b").groupMap(_._2)(_._1)
// Map("b" -> List(2, 4), "a" -> List(1))
यह:
group
उनके दूसरे टपल भाग ( _._2
) ( ग्रुप मैप का समूह भाग) पर आधारित तत्व
map
अपनी पहली टपल हिस्सा (लेने के आधार पर वर्गीकृत आइटम एस _._1
) (के समूह हिस्सा नक्शा मानचित्र )
इसे वन-पास संस्करण के रूप में देखा जा सकता है map.groupBy(_._2).mapValues(_.map(_._1))
।
Map[K, C[V]]
में तब्दील नहीं होगा Map[V, C[K]]
।
उलटा इस ऑपरेशन के लिए एक बेहतर नाम है, जैसे कि "एक गणितीय फ़ंक्शन का उलटा")
मैं अक्सर यह उलटा रूपांतरण न केवल नक्शे पर बल्कि अन्य (Seq सहित) संग्रह पर करता हूं। मुझे सबसे अच्छा लगता है कि अपने उलटे ऑपरेशन की परिभाषा को एक-से-एक नक्शे तक सीमित न करना। यहां मैं मानचित्रों के साथ परिभाषा करता हूं (कृपया मेरे कार्यान्वयन में सुधार सुझाएं)।
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
}
यदि यह एक-से-एक नक्शा है, तो आप सिंगलटन सूचियों के साथ समाप्त होते हैं, जिन्हें तुच्छ रूप से परीक्षण किया जा सकता है और नक्शे [बी, सूची [ए]] के बजाय मानचित्र [बी, ए] में तब्दील किया जा सकता है।
हम इस 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))
Map(1 -> "A", 2 -> "B", 3 -> "B").map(_.swap)
परिणामMap(A -> 1, B -> 3)