एक संग्रह को मानचित्र-दर-कुंजी में बदलने का स्काला सबसे अच्छा तरीका है?


165

अगर मेरे पास संग्रह cका प्रकार है Tऔर ( pपर , Tटाइप P) पर एक संपत्ति है , तो मानचित्र-दर-निष्कर्षण-कुंजी करने का सबसे अच्छा तरीका क्या है ?

val c: Collection[T]
val m: Map[P, T]

एक तरीका निम्नलिखित है:

m = new HashMap[P, T]
c foreach { t => m add (t.getP, t) }

लेकिन अब मुझे एक परिवर्तनशील मानचित्र की आवश्यकता है । क्या ऐसा करने का एक बेहतर तरीका है कि यह 1 पंक्ति में है और मैं एक अपरिवर्तनीय मानचित्र के साथ समाप्त होता हूं ? (स्पष्ट रूप से मैं उपरोक्त को एक साधारण पुस्तकालय उपयोगिता में बदल सकता हूं, जैसा कि मैं जावा में करूंगा, लेकिन मुझे संदेह है कि स्काला में कोई भी नहीं है)

जवाबों:


232

आप उपयोग कर सकते हैं

c map (t => t.getP -> t) toMap

लेकिन ध्यान रहे कि इसके लिए 2 ट्रैवर्स की जरूरत होती है।


8
मैं अभी भी एक के टीआरसी में मेरे सुझावों को पसंद करता हूं Traversable[K].mapTo( K => V)और Traversable[V].mapBy( V => K)बेहतर था!
बजे

7
ज्ञात हो कि यह एक द्विघात ऑपरेशन है, लेकिन यहां दिए गए अधिकांश अन्य वेरिएंट के लिए भी यही है। Scala.collection.mutable.MapBuilder आदि के स्रोत कोड को देखते हुए, यह मुझे लगता है कि प्रत्येक ट्यूपल के लिए, एक नया अपरिवर्तनीय मानचित्र बनाया जाता है जिसमें टपल जोड़ा जाता है।
jcsahnwaldt

30
500,000 तत्वों के साथ एक सूची के लिए मेरी मशीन पर, यह स्काला कोड सीधे-फॉरवर्ड जावा दृष्टिकोण की तुलना में लगभग 20 गुना धीमा है (उचित आकार के साथ हैशपॉप बनाएं, सूची में लूप, नक्शे में तत्वों को डालें)। 5,000 तत्वों के लिए, स्काला लगभग 8 गुना धीमा है। स्काला में लिखा गया लूप अप्रोच, वैरिएंट वैरिएंट की तुलना में 3 गुना तेज है, लेकिन फिर भी जावा की तुलना में 2 से 7 गुना धीमा है।
jcsahnwaldt

8
क्या आप एसओ समुदाय को परीक्षण स्रोत प्रदान करेंगे? धन्यवाद।
user573215

8
बदलें cसाथ c.iteratorमध्यवर्ती संग्रह का से बचने के निर्माण के लिए।
ghik

21

आप tuples की एक चर संख्या के साथ एक मानचित्र का निर्माण कर सकते हैं। अतः इसे टुपल्स के संग्रह में बदलने के लिए संग्रह पर मानचित्र विधि का उपयोग करें और फिर परिणाम को एक चर तर्क में बदलने के लिए: _ * चाल का उपयोग करें।

scala> val list = List("this", "maps", "string", "to", "length") map {s => (s, s.length)}
list: List[(java.lang.String, Int)] = List((this,4), (maps,4), (string,6), (to,2), (length,6))

scala> val list = List("this", "is", "a", "bunch", "of", "strings")
list: List[java.lang.String] = List(this, is, a, bunch, of, strings)

scala> val string2Length = Map(list map {s => (s, s.length)} : _*)
string2Length: scala.collection.immutable.Map[java.lang.String,Int] = Map(strings -> 7, of -> 2, bunch -> 5, a -> 1, is -> 2, this -> 4)

5
मैं स्कैला के बारे में> 2 सप्ताह से पढ़ रहा हूं और उदाहरणों के माध्यम से काम कर रहा हूं और एक बार भी मैंने यह नहीं देखा है: "_ *" संकेतन! आपकी मदद के लिए बहुत बहुत धन्यवाद
oxbow_lakes

सिर्फ रिकॉर्ड के लिए, मुझे आश्चर्य है कि हमें सटीक जानकारी की आवश्यकता क्यों है कि यह _ के साथ एक अनुक्रम है । मानचित्र अभी भी यहाँ tuple की सूची लौटाता है। तो क्यों _ ? मेरा मतलब है कि यह काम करता है लेकिन मैं यहाँ टाइप टाइप को समझना चाहता हूँ
MaatDeamon

1
क्या यह अन्य विधियों की तुलना में अधिक कुशल है?
जुस 12

16

@ जेम्स इरी के समाधान के अलावा, एक तह का उपयोग करके इसे पूरा करना भी संभव है। मुझे संदेह है कि यह समाधान टपल विधि की तुलना में थोड़ा तेज है (कम कचरा वस्तुओं का निर्माण होता है):

val list = List("this", "maps", "string", "to", "length")
val map = list.foldLeft(Map[String, Int]()) { (m, s) => m(s) = s.length }

मैं इसे आज़माऊंगा (मुझे यकीन है कि यह काम करता है :-) "(M, s) => m (s) = s.length" फ़ंक्शन के साथ क्या हो रहा है? मैंने एक योग और एक फ़ंक्शन "_ + _" के साथ विशिष्ट फोल्डलिफ्ट उदाहरण देखा है; यह बहुत अधिक भ्रमित है! फ़ंक्शन को लगता है कि मेरे पास पहले से ही एक टपल (m, s) है, जो मुझे वास्तव में नहीं मिलता है
oxbow_lakes

2
यार, स्काला अजीब था फिर वापस!
9

8
@ डैनियल मैं आपके कोड की कोशिश करता हूं, लेकिन निम्नलिखित त्रुटि दिखाई देती है: "मूल्य अद्यतन scala.collection.immutable.Map [स्ट्रिंग, इंट] का सदस्य नहीं है"। कृपया अपने कोड को समझाएं कि यह कोड कैसे काम करता है?
mr.boyfox

1
काम करने के लिए प्रतीत नहीं होता है। मेरे लिए या तो "अनुप्रयोग पैरामीटर नहीं लेता है"
jayunit100

7
अपरिवर्तनीय संस्करण list.foldLeft(Map[String,Int]()) { (m,s) => m + (s -> s.length) }:। ध्यान दें कि यदि आप ट्यूपल के निर्माण के लिए अल्पविराम का उपयोग करना चाहते हैं, तो आपको कोष्ठक की एक अतिरिक्त जोड़ी की आवश्यकता है ((s, s.length)):।
केल्विन

11

इसे अनुवर्ती रूप से लागू किया जा सकता है और संग्रह के माध्यम से निम्नानुसार एकल ट्रैवर्सल के साथ लागू किया जा सकता है।

val map = c.foldLeft(Map[P, T]()) { (m, t) => m + (t.getP -> t) }

समाधान काम करता है क्योंकि एक अपरिवर्तनीय मानचित्र में जोड़ने से अतिरिक्त प्रविष्टि के साथ एक नया अपरिवर्तनीय मानचित्र मिलता है और यह मान गुना ऑपरेशन के माध्यम से संचायक के रूप में कार्य करता है।

ट्रेडऑफ़ यहाँ कोड की सादगी बनाम इसकी दक्षता है। इसलिए, बड़े संग्रह के लिए, यह दृष्टिकोण लागू होने mapऔर जैसे 2 ट्रैवर्सल कार्यान्वयन का उपयोग करने से अधिक उपयुक्त हो सकता है toMap


8

एक अन्य समाधान (सभी प्रकार के लिए काम नहीं कर सकता है)

import scala.collection.breakOut
val m:Map[P, T] = c.map(t => (t.getP, t))(breakOut)

यह मध्यस्थ सूची के निर्माण से बचता है, यहां अधिक जानकारी: स्काला 2.8 ब्रेकआउट


7

आप जो हासिल करने की कोशिश कर रहे हैं वह थोड़ा अपरिभाषित है।
क्या होगा अगर दो या अधिक सामान cएक ही हिस्से में p? pमानचित्र में किस आइटम को मैप किया जाएगा ?

इसे देखने का अधिक सटीक तरीका यह है कि pसभी cवस्तुओं के बीच एक नक्शा तैयार करना है:

val m: Map[P, Collection[T]]

यह आसानी से GroupBy के साथ प्राप्त किया जा सकता है :

val m: Map[P, Collection[T]] = c.groupBy(t => t.p)

यदि आप अभी भी मूल नक्शा चाहते हैं, तो आप उदाहरण के लिए, pपहले वाले नक्शे पर tयह कर सकते हैं:

val m: Map[P, T] = c.groupBy(t => t.p) map { case (p, ts) =>  p -> ts.head }

1
इस पर एक आसान ट्विक के collectबजाय उपयोग करना है map। उदाहरण के लिए: c.group(t => t.p) collect { case (Some(p), ts) => p -> ts.head }। इस तरह आप एक विकल्प [_] होने पर चाबी को समतल कर सकते हैं।
१६/१६

@healsjnr ज़रूर, यह किसी भी नक्शे के लिए कहा जा सकता है। यह हालांकि यहाँ मूल मुद्दा नहीं है।
ईयाल रोथ

1
आप .mapValues(_.head)मानचित्र के बजाय उपयोग कर सकते हैं ।
lex82

2

यह संभवतः सूची को मानचित्र में बदलने का सबसे कारगर तरीका नहीं है, लेकिन यह कॉलिंग कोड को अधिक पठनीय बनाता है। मैंने सूची में एक मेप विधि जोड़ने के लिए अंतर्निहित रूपांतरण का उपयोग किया :

implicit def list2ListWithMapBy[T](list: List[T]): ListWithMapBy[T] = {
  new ListWithMapBy(list)
}

class ListWithMapBy[V](list: List[V]){
  def mapBy[K](keyFunc: V => K) = {
    list.map(a => keyFunc(a) -> a).toMap
  }
}

कॉलिंग कोड उदाहरण:

val list = List("A", "AA", "AAA")
list.mapBy(_.length)                  //Map(1 -> A, 2 -> AA, 3 -> AAA)

ध्यान दें कि अंतर्निहित रूपांतरण के कारण, कॉलर कोड को scala के निहितार्थ आयात करने की आवश्यकता होती है।


2
c map (_.getP) zip c

अच्छी तरह से काम करता है और बहुत intuitiv है


8
कृपया अधिक जानकारी जोड़ें।
सैयदा जुनायरा

2
मुझे माफ कर दो। लेकिन, इस सवाल का जवाब "एक संग्रह को मानचित्र-दर-कुंजी में बदलने का सबसे अच्छा तरीका है?" जैसा कि बेन लिंग्स है।
जोर्ग बैशटिगर

1
और बेन ने कोई स्पष्टीकरण नहीं दिया?
शिंज़ौ

1
यह दो सूचियों को बनाता है और cकुंजी (सॉर्ट) के तत्वों का उपयोग करके "मानचित्र" में संयोजित होता है । नोट "मानचित्र" क्योंकि परिणामी संग्रह एक स्कैला नहीं है, बल्कि एक Mapऔर सूची बनाता है / टुपल्स के चलने योग्य ... लेकिन प्रभाव ओपी के उद्देश्य के लिए समान है, मैं सादगी को छूट नहीं दूंगा लेकिन यह foldLeftसमाधान के रूप में कुशल नहीं है , और न ही यह सवाल का असली जवाब "एक संग्रह को मानचित्र-बाय-की में परिवर्तित करना"
डेक्सटर लेगास्पि

2

कैसे ज़िप और toMap का उपयोग करने के बारे में?

myList.zip(myList.map(_.length)).toMap

1

इसके लायक क्या है, इसे करने के दो निरर्थक तरीके हैं:

scala> case class Foo(bar: Int)
defined class Foo

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._

scala> val c = Vector(Foo(9), Foo(11))
c: scala.collection.immutable.Vector[Foo] = Vector(Foo(9), Foo(11))

scala> c.map(((_: Foo).bar) &&& identity).toMap
res30: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))

scala> c.map(((_: Foo).bar) >>= (Pair.apply[Int, Foo] _).curried).toMap
res31: scala.collection.immutable.Map[Int,Foo] = Map(9 -> Foo(9), 11 -> Foo(11))

इसके अलावा, fwiw, यह है कि उन दोनों को हास्केल में कैसा दिखेगा: Map.fromList $ map (bar &&& id) c, Map.fromList $ map (bar >>= (,)) c
10

-1

यह मेरे लिए काम करता है:

val personsMap = persons.foldLeft(scala.collection.mutable.Map[Int, PersonDTO]()) {
    (m, p) => m(p.id) = p; m
}

मैप को म्यूटेबल करना पड़ता है और एक म्यूटेबल मैप में जोड़ने के बाद मैप को वापस लौटना पड़ता है।


1
वास्तव में, इसे निम्नानुसार अपरिवर्तनीय रूप से लागू किया जा सकता है: val personsMap = persons.foldLeft(Map[Int, PersonDTO]()) { (m, p) => m + (p.id -> p) }जैसा कि ऊपर उल्लेखित है, नक्शा अपरिवर्तनीय हो सकता है, क्योंकि अपरिवर्तनीय मानचित्र में जोड़ने से अतिरिक्त प्रविष्टि के साथ एक नया अपरिवर्तनीय मानचित्र वापस आ जाता है। यह मान गुना ऑपरेशन के माध्यम से संचायक के रूप में कार्य करता है।
रामवृक्ष

-2

मानचित्र के साथ संग्रह पर मानचित्र () का उपयोग करें

val map = list.map(e => (e, e.length)).toMap

3
7 साल पहले प्रस्तुत किए गए और स्वीकार किए गए उत्तर से यह कैसे अलग है?
jwvh

-4

अगर Json String (json फ़ाइल को पढ़ना) से scala Map में परिवर्तित करना

import spray.json._
import DefaultJsonProtocol._

val jsonStr = Source.fromFile(jsonFilePath).mkString
val jsonDoc=jsonStr.parseJson
val map_doc=jsonDoc.convertTo[Map[String, JsValue]]

// Get a Map key value
val key_value=map_doc.get("key").get.convertTo[String]

// If nested json, re-map it.
val key_map=map_doc.get("nested_key").get.convertTo[Map[String, JsValue]]
println("Nested Value " + key_map.get("key").get)

यह 11 साल पुराना सवाल JSON के बारे में कुछ नहीं पूछता है। आपका उत्तर स्थान से बाहर है।
jwvh
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.