टपल की सूची को मानचित्र में बदलें (और डुप्लिकेट कुंजी से निपटें?)


90

मैं नक़ल की कुंजी [("a","b"),("c","d"),("a","f")]को मैप में डुप्लिकेट कुंजी के साथ बदलने के लिए एक अच्छे तरीके के बारे में सोच रहा था ("a" -> ["b", "f"], "c" -> ["d"])। आम तौर पर (अजगर में), मैं सूची में एक खाली नक्शा और फॉर-लूप बनाऊंगा और डुप्लिकेट कुंजी की जांच करूंगा। लेकिन मैं यहां कुछ और स्काला-ईश और चतुर समाधान ढूंढ रहा हूं।

btw, कुंजी-मूल्य का वास्तविक प्रकार जो मैं यहाँ उपयोग कर रहा हूं वह है (Int, Node)और मैं इसके मानचित्र में बदलना चाहता हूं(Int -> NodeSeq)

जवाबों:


78

समूह और फिर परियोजना:

scala> val x = List("a" -> "b", "c" -> "d", "a" -> "f")
//x: List[(java.lang.String, java.lang.String)] = List((a,b), (c,d), (a,f))
scala> x.groupBy(_._1).map { case (k,v) => (k,v.map(_._2))}
//res1: scala.collection.immutable.Map[java.lang.String,List[java.lang.String]] = Map(c -> List(d), a -> List(b, f))

गुना का उपयोग करने के लिए और अधिक शानदार तरीका, वहाँ की तरह (स्किप map fकदम)।


124

ऐसे डुप्लिकेट के लिए, जो डुप्लिकेट हैंडलिंग नीति से डुप्लिकेट या ठीक होने की उम्मीद नहीं करते हैं :

List("a" -> 1, "b" -> 2).toMap
// Result: Map(a -> 1, c -> 2)

2.12 तक, डिफ़ॉल्ट नीति पढ़ती है:

डुप्लिकेट कुंजियों को बाद की कुंजियों द्वारा अधिलेखित किया जाएगा: यदि यह एक अनियोजित संग्रह है, तो परिणामी मानचित्र में कौन सी कुंजी अपरिभाषित है।


56

यहाँ एक और विकल्प है:

x.groupBy(_._1).mapValues(_.map(_._2))

यह हमें एक Map[String, SeqView[String,Seq[_]]]... क्या यह जानबूझकर है?
लुइगी प्लिंज

1
@ लुइगीपलिंग ए SeqView[String,Seq[_]]भी है Seq[String]। फिर भी मैं नहीं सोचता कि यह सार्थक है, इसलिए मैंने इसे हटा दिया viewmapValuesमूल्यों पर वैसे भी एक विचार करेंगे।
डैनियल सी। सोबरल

इसने मेरे मामले के लिए पूरी तरह से काम किया (coursera homework): lazy val Dictionary curWord)} pair.groupBy ( ._1) .mapValues ​​(.map (_._ 2))}
जेसन

mapValues ​​एक नक्शे का दृश्य देता है, न कि एक नया नक्शा scala-lang.org/api/current/index.html#scala.collection.Map
Max Heiber

1
शायद चाहते हैं x.groupBy(_._1).mapValues(_.map(_._2)).map(identity)क्योंकि mapValuesअभिव्यक्ति का उपयोग किए जाने पर हर बार पुन: प्रतिष्ठित किया जाएगा। मुद्दों को
जेफरी एगुइलेरा

20

डुप्लिकेट के बारे में परवाह करने वाले Googlers के लिए:

implicit class Pairs[A, B](p: List[(A, B)]) {
  def toMultiMap: Map[A, List[B]] = p.groupBy(_._1).mapValues(_.map(_._2))
}

> List("a" -> "b", "a" -> "c", "d" -> "e").toMultiMap
> Map("a" -> List("b", "c"), "d" -> List("e")) 

12

प्रारंभ Scala 2.13, अधिकांश संग्रह समूह मानचित्र विधि के साथ प्रदान किए जाते हैं जो (जैसा कि इसके नाम से पता चलता है) एक समकक्ष (अधिक कुशल) groupByइसके बाद है mapValues:

List("a" -> "b", "c" -> "d", "a" -> "f").groupMap(_._1)(_._2)
// Map[String,List[String]] = Map(a -> List(b, f), c -> List(d))

यह:

  • groupटुपल्स के पहले भाग पर आधारित तत्व ( समूह मानचित्र का समूह भाग )

  • mapअपने दूसरे टपल भाग (समूह मानचित्र का नक्शा भाग ) को ले कर समूहीकृत मूल्य

यह एक बराबर है, list.groupBy(_._1).mapValues(_.map(_._2))लेकिन सूची के माध्यम से एक पास में प्रदर्शन किया जाता है


4

डुप्लिकेट कीज़ को हैंडल करने वाले ट्यूपल्स की सूची को मैप में बदलने के लिए यहां एक अधिक स्काला मुहावरेदार तरीका है। आप एक तह का उपयोग करना चाहते हैं।

val x = List("a" -> "b", "c" -> "d", "a" -> "f")

x.foldLeft(Map.empty[String, Seq[String]]) { case (acc, (k, v)) =>
  acc.updated(k, acc.getOrElse(k, Seq.empty[String]) ++ Seq(v))
}

res0: scala.collection.immutable.Map[String,Seq[String]] = Map(a -> List(b, f), c -> List(d))

1
आपको क्यों लगता है कि यह ग्रुप-मैप-वाल्यू समाधान की तुलना में अधिक स्काला-शैली है जो यहां प्रदान की गई है?
Make42

@ om-nom-nom स्टेटमेंट "फोल्ड का उपयोग करने के लिए अधिक स्केलिश तरीका, वहां की तरह (मैप मैप चरण को छोड़ें)।"
केवरिस

मैं एक तार्किक तर्क के लिए उम्मीद कर रहा था ;-)। न तो ओम-नोम-नोम और न ही लिंक किए गए लेख ने मेरे प्रश्न के लिए सबूत प्रदान किए। (या क्या मुझे यह याद है?)
Make42

1
@ Make42 इससे निपटने के लिए एक और अधिक fp तरीका है, क्योंकि सभी मोनड्स मोनॉयड हैं, और कानून द्वारा मोनॉयड्स फोल्डेबल हैं। Fp में, ऑब्जेक्ट्स और इवेंट्स को मोनड्स के रूप में तैयार किया जाता है, और सभी मोनड्स ग्रुपबी को लागू नहीं करेंगे।
सोख लें

4

नीचे आप कुछ समाधान पा सकते हैं। (GroupBy, FoldLeft, Aggregate, Spark)

val list: List[(String, String)] = List(("a","b"),("c","d"),("a","f"))

GroupBy भिन्नता

list.groupBy(_._1).map(v => (v._1, v._2.map(_._2)))

बाएं बदलाव को मोड़ो

list.foldLeft[Map[String, List[String]]](Map())((acc, value) => {
  acc.get(value._1).fold(acc ++ Map(value._1 -> List(value._2))){ v =>
    acc ++ Map(value._1 -> (value._2 :: v))
  }
})

एग्रीगेट वेरिएशन - लेफ्ट को फोल्ड करने के समान

list.aggregate[Map[String, List[String]]](Map())(
  (acc, value) => acc.get(value._1).fold(acc ++ Map(value._1 -> 
    List(value._2))){ v =>
     acc ++ Map(value._1 -> (value._2 :: v))
  },
  (l, r) => l ++ r
)

स्पार्क भिन्नता - बड़े डेटा सेटों के लिए (RDD में रूपांतरण और RDD से सादा मानचित्र के लिए)

import org.apache.spark.rdd._
import org.apache.spark.{SparkContext, SparkConf}

val conf: SparkConf = new 
SparkConf().setAppName("Spark").setMaster("local")
val sc: SparkContext = new SparkContext (conf)

// This gives you a rdd of the same result
val rdd: RDD[(String, List[String])] = sc.parallelize(list).combineByKey(
   (value: String) => List(value),
   (acc: List[String], value) => value :: acc,
   (accLeft: List[String], accRight: List[String]) => accLeft ::: accRight
)

// To convert this RDD back to a Map[(String, List[String])] you can do the following
rdd.collect().toMap

2

आप यह कोशिश कर सकते हैं

scala> val b = new Array[Int](3)
// b: Array[Int] = Array(0, 0, 0)
scala> val c = b.map(x => (x -> x * 2))
// c: Array[(Int, Int)] = Array((1,2), (2,4), (3,6))
scala> val d = Map(c : _*)
// d: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 4, 3 -> 6)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.