स्केल सूची को टुपल में बदलें?


88

मैं 3 तत्वों के साथ एक सूची को आकार 3 के टपल में कैसे बदल सकता हूं?

उदाहरण के लिए, मान लें कि मेरे पास है val x = List(1, 2, 3)और मैं इसे रूपांतरित करना चाहता हूं (1, 2, 3)। मैं यह कैसे कर सकता हूँ?


1
यह संभव नहीं है ("हाथ से छोड़कर") AFAIK। यह देखते हुए def toTuple(x: List[Int]): R, R का प्रकार क्या होना चाहिए?

7
यदि इसे एक मनमाने आकार के टपल के लिए करने की आवश्यकता नहीं है (अर्थात ऊपर प्रस्तुत एक काल्पनिक विधि की तरह), विचार करें x match { case a :: b :: c :: Nil => (a, b, c); case _ => (0, 0, 0) }और नोट करें कि परिणामी प्रकार तय हो गया हैTuple3[Int,Int,Int]

2
जब आप जो करना चाहते हैं वह संभव नहीं है List, तो आप Shapeless ' HListप्रकार में देख सकते हैं , जो कि tuples ( github.com/milessabin/… ) से रूपांतरण की अनुमति देता है । शायद यह आपके उपयोग के मामले के लिए लागू हो।

जवाबों:


59

आप इसे एक प्रकार से नहीं कर सकते। क्यों? क्योंकि सामान्य तौर पर हम रनटाइम तक किसी सूची की लंबाई नहीं जान सकते। लेकिन एक टपल की "लंबाई" को इसके प्रकार में एन्कोड किया जाना चाहिए, और इसलिए संकलन समय पर जाना जाता है। उदाहरण के लिए, (1,'a',true)प्रकार है (Int, Char, Boolean), जो चीनी के लिए है Tuple3[Int, Char, Boolean]। ट्यूपल्स के कारण यह प्रतिबंध है कि उन्हें गैर-सजातीय प्रकारों को संभालने में सक्षम होने की आवश्यकता है।


क्या समान प्रकार के तत्वों की कुछ निश्चित आकार की सूची है? अस्वाभाविक पुस्तकालयों को आयात नहीं करना, जैसे आकारहीन, बिल्कुल।

1
@davips मुझे नहीं पता, लेकिन यह अपना खुद का बनाने के लिए काफी आसान है, जैसेcase class Vec3[A](_1: A, _2: A, _3: A)
टॉम क्रोकेट

यह उसी प्रकार के तत्वों का एक "टपल" होगा, मैं उदाहरण के लिए, इस पर नक्शा लागू नहीं कर सकता।

1
किसी भी नए डेटा प्रकार के साथ @davips आपको यह परिभाषित करना होगा कि mapआदि इसके लिए कैसे काम करता है
टॉम क्रोकेट

1
इस तरह की सीमा कुछ और से अधिक प्रकार की सुरक्षा के बेकार होने का एक शानदार संकेतक प्रतीत होती है। यह मुझे याद दिलाता है "खाली सेट में कई दिलचस्प गुण हैं।"
एली

58

आप इसे स्काला एक्सट्रैक्टर्स और पैटर्न मैचिंग ( लिंक ) का उपयोग करके कर सकते हैं :

val x = List(1, 2, 3)

val t = x match {
  case List(a, b, c) => (a, b, c)
}

जो टपल लौटाता है

t: (Int, Int, Int) = (1,2,3)

इसके अलावा, यदि आप सूची के आकार के बारे में निश्चित नहीं हैं, तो आप वाइल्डकार्ड ऑपरेटर का उपयोग कर सकते हैं

val t = x match {
  case List(a, b, c, _*) => (a, b, c)
}

4
इस समाधान के संदर्भ में, टाइप-सेफ्टी के बारे में शिकायतों का मतलब है कि आपको रनटाइम पर एक मैच्योर हो सकता है। यदि आप चाहते हैं, तो आप उस त्रुटि को पकड़ सकते हैं और कुछ कर सकते हैं यदि सूची में गलत लंबाई है। इस समाधान की एक और अच्छी विशेषता यह है कि आउटपुट को टपल नहीं होना पड़ता है, यह आपके स्वयं के कस्टम वर्गों या संख्याओं के कुछ परिवर्तन में से एक हो सकता है। मुझे नहीं लगता कि आप इसे गैर-सूचियों के साथ कर सकते हैं, हालांकि (इसलिए आपको इनपुट के लिए एक .toList ऑपरेशन करने की आवश्यकता हो सकती है)।
जिम पीवार्स्की

आप इसे +: सिंटैक्स का उपयोग करके किसी भी प्रकार के स्काला अनुक्रम के साथ कर सकते हैं। इसके अलावा, एक पकड़-सभी को जोड़ने के लिए मत भूलना
ig-dev

48

निराकार का उपयोग कर एक उदाहरण :

import shapeless._
import syntax.std.traversable._
val x = List(1, 2, 3)
val xHList = x.toHList[Int::Int::Int::HNil]
val t = xHList.get.tupled

नोट: कंपाइलर को HList में सूची बदलने के लिए कुछ प्रकार के informations की आवश्यकता होती है, यही कारण है कि आपको toHListविधि में टाइप informations को पास करने की आवश्यकता है


18

शापलेस 2.0 ने कुछ सिंटैक्स को बदल दिया। यहां आकारहीन का उपयोग करके अद्यतन समाधान है।

import shapeless._
import HList._
import syntax.std.traversable._

val x = List(1, 2, 3)
val y = x.toHList[Int::Int::Int::HNil]
val z = y.get.tupled

मुख्य मुद्दा यह है कि प्रकार .toHList के लिए को समय से पहले निर्दिष्ट किया जाना चाहिए। अधिक आम तौर पर, चूंकि टूपल उनकी धमनी में सीमित होते हैं, इसलिए आपके सॉफ़्टवेयर का डिज़ाइन एक अलग समाधान द्वारा बेहतर ढंग से परोसा जा सकता है।

फिर भी, यदि आप एक सूची को वैधानिक रूप से बना रहे हैं, तो इस तरह के एक समाधान पर विचार करें, आकारहीन का उपयोग करके भी। यहां, हम सीधे एक HList बनाते हैं और संकलन समय पर उपलब्ध होता है। याद रखें कि एक HList में सूची और Tuple दोनों प्रकार की विशेषताएं हैं। अर्थात इसमें टपल की तरह विभिन्न प्रकार के तत्व हो सकते हैं और मानक संग्रह जैसे अन्य कार्यों के बीच मैप किए जा सकते हैं। HLists थोड़ा समय लेते हैं, हालांकि आप नए हैं तो धीरे-धीरे चलने के लिए उपयोग करें।

scala> import shapeless._
import shapeless._

scala> import HList._
import HList._

scala>   val hlist = "z" :: 6 :: "b" :: true :: HNil
hlist: shapeless.::[String,shapeless.::[Int,shapeless.::[String,shapeless.::[Boolean,shapeless.HNil]]]] = z :: 6 :: b :: true :: HNil

scala>   val tup = hlist.tupled
tup: (String, Int, String, Boolean) = (z,6,b,true)

scala> tup
res0: (String, Int, String, Boolean) = (z,6,b,true)

13

सादगी और किसी भी लंबाई की सूचियों के लिए नहीं होने के बावजूद, यह टाइप-सेफ है और ज्यादातर मामलों में इसका जवाब है:

val list = List('a','b')
val tuple = list(0) -> list(1)

val list = List('a','b','c')
val tuple = (list(0), list(1), list(2))

एक और संभावना है, जब आप सूची को नाम नहीं देना चाहते हैं और न ही इसे दोहराना चाहते हैं (मुझे आशा है कि कोई व्यक्ति Seq / अन्य भागों से बचने का कोई रास्ता दिखा सकता है):

val tuple = Seq(List('a','b')).map(tup => tup(0) -> tup(1)).head
val tuple = Seq(List('a','b','c')).map(tup => (tup(0), tup(1), tup(2))).head

10

एफडब्ल्यूआईडब्ल्यू , मुझे कई क्षेत्रों में ट्यूलल चाहिए था और टपल असाइनमेंट के सिंटैक्टिक शुगर का उपयोग करना चाहता था। ईजी:

val (c1, c2, c3) = listToTuple(myList)

यह पता चला है कि एक सूची की सामग्री को भी असाइन करने के लिए वाक्य रचना चीनी है ...

val c1 :: c2 :: c3 :: Nil = myList

तो अगर आप एक ही समस्या है tuples के लिए कोई ज़रूरत नहीं है।


@javadba मैं देख रहा था कि कैसे लिस्ट को लागू किया जाए TTTlele () लेकिन समाप्त करने की आवश्यकता नहीं है। लिस्ट सिंथैटिक शुगर ने मेरी समस्या हल कर दी।
पीटर एल

एक और वाक्यविन्यास भी है, जो मेरी राय में थोड़ा बेहतर है:val List(c1, c2, c3) = myList
कोलमार

7

आप इसे एक प्रकार से सुरक्षित तरीके से नहीं कर सकते। स्काला में, सूचियाँ कुछ प्रकार के तत्वों के मनमाने ढंग से लंबाई वाले अनुक्रम हैं। जहाँ तक प्रकार प्रणाली को जानता है,x वह मनमानी लंबाई की सूची हो सकती है।

इसके विपरीत, एक टपल की समता को संकलन समय पर जाना जाना चाहिए। यह असाइन करने की अनुमति देने के लिए प्रकार प्रणाली की सुरक्षा गारंटी का उल्लंघन करेगाx टपल प्रकार को करने की ।

वास्तव में, तकनीकी कारणों से, स्केल ट्यूपल 22 तत्वों तक सीमित थे , लेकिन सीमा अब 2.11 में मौजूद नहीं है। 2.11 में केस क्लास की सीमा को हटा दिया गया है। https://github.com/scala/scala/pull/2305

एक फ़ंक्शन को मैन्युअल रूप से कोड करना संभव होगा जो 22 तत्वों की सूचियों को परिवर्तित करता है, और बड़ी सूची के लिए एक अपवाद फेंकता है। स्काला का टेम्पलेट समर्थन, एक आगामी विशेषता, इसे और अधिक संक्षिप्त बना देगा। लेकिन यह एक बदसूरत हैक होगा।


क्या इस काल्पनिक कार्य का परिणामी प्रकार कोई होगा?

मामला कक्षा की सीमा 2.11 github.com/scala/scala/pull/2305
gdoubleod

5

यदि आप बहुत सुनिश्चित हैं कि आपकी सूची। 23 का उपयोग करें:

def listToTuple[A <: Object](list:List[A]):Product = {
  val class = Class.forName("scala.Tuple" + list.size)
  class.getConstructors.apply(0).newInstance(list:_*).asInstanceOf[Product]
}
listToTuple: [A <: java.lang.Object](list: List[A])Product

scala> listToTuple(List("Scala", "Smart"))
res15: Product = (Scala,Smart)

5

इसका shapelessउपयोग कम बॉयलरप्लेट के साथ भी किया जा सकता है Sized:

scala> import shapeless._
scala> import shapeless.syntax.sized._

scala> val x = List(1, 2, 3)
x: List[Int] = List(1, 2, 3)

scala> x.sized(3).map(_.tupled)
res1: Option[(Int, Int, Int)] = Some((1,2,3))

यह टाइप-सुरक्षित है: आपको मिलता है None, अगर टपल का आकार गलत है, लेकिन टपल का आकार एक शाब्दिक या final val(परिवर्तनीय होना चाहिए shapeless.Nat) होना चाहिए ।


यह 22 से बड़े आकारों के लिए काम नहीं करता है, कम से कम
आकारहीन_2.11 के

@kfkhalili हाँ, और यह एक आकारहीन सीमा नहीं है। स्केला 2 खुद 22 से अधिक तत्वों के साथ ट्यूपल्स की अनुमति नहीं देता है, इसलिए किसी भी विधि का उपयोग करके बड़े आकार की सूची को टुपल में बदलना संभव नहीं है।
कोलमार

4

पैटर्न मिलान का उपयोग करना:

val intTuple = सूची (1,2,3) मैच {केस सूची (ए, बी, सी) => (ए, बी, सी)}


इस प्रश्न का उत्तर देते समय यह पुराना (6 वर्ष से अधिक) यह अक्सर एक अच्छा विचार है कि आपका उत्तर पहले से प्रस्तुत सभी (12) पुराने उत्तरों से अलग कैसे है। विशेष रूप से, आपका उत्तर केवल तभी लागू होता है जब List/ की लंबाई Tupleएक ज्ञात स्थिरांक हो।
jwvh

धन्यवाद @ jwvh, आपकी टिप्पणियों को आगे बढ़ाने पर विचार करेगा।
माइकल ओलाफिसोए

2

2015 की पोस्ट। के लिए टॉम Crockett का जवाब भी अधिक होने की स्पष्ट है, यहाँ कोई वास्तविक उदाहरण है।

सबसे पहले, मैं इसके बारे में भ्रमित हो गया। क्योंकि मैं पायथन से आता हूं, जहां आप बस कर सकते हैं tuple(list(1,2,3))
क्या यह स्काला भाषा से कम है? (उत्तर है - यह स्काला या पायथन के बारे में नहीं है, यह स्थैतिक-प्रकार और गतिशील-प्रकार के बारे में है।)

यही कारण है कि मुझे क्रूक्स को खोजने की कोशिश कर रहा है कि स्काला ऐसा क्यों नहीं कर सकता है।


निम्न कोड उदाहरण एक toTupleविधि को लागू करता है, जिसमें टाइप-सेफ toTupleNऔर टाइप-असुरक्षित है toTuple

toTupleविधि, रन-टाइम में टाइप-लंबाई सूचना संकलन समय पर यानी कोई प्रकार- लंबाई जानकारी प्राप्त तो वापसी प्रकार है Productजो बहुत ही अजगर की तरह है tupleवास्तव में (कोई प्रत्येक स्थिति में प्रकार, और प्रकार की कोई लंबाई)।
उस प्रकार को रनटाइम त्रुटि के लिए टाइप-मिसमैच या कहा जाता हैIndexOutOfBoundException । (इसलिए पायथन की सुविधाजनक सूची-टू-ट्यूपल मुफ्त दोपहर का भोजन नहीं है।)

इसके विपरीत, यह उपयोगकर्ता द्वारा प्रदान की गई लंबाई की जानकारी है जो toTupleNसंकलन-समय को सुरक्षित बनाती है।

implicit class EnrichedWithToTuple[A](elements: Seq[A]) {
  def toTuple: Product = elements.length match {
    case 2 => toTuple2
    case 3 => toTuple3
  }
  def toTuple2 = elements match {case Seq(a, b) => (a, b) }
  def toTuple3 = elements match {case Seq(a, b, c) => (a, b, c) }
}

val product = List(1, 2, 3).toTuple
product.productElement(5) //runtime IndexOutOfBoundException, Bad ! 

val tuple = List(1, 2, 3).toTuple3
tuple._5 //compiler error, Good!

अच्छा लग रहा है - इसे अभी
आज़माएं

2

आप भी ऐसा कर सकते हैं

  1. पैटर्न-मिलान (जो आप नहीं चाहते हैं) या
  2. सूची के माध्यम से पुनरावृत्ति और प्रत्येक तत्व को एक-एक करके लागू करना।

    val xs: Seq[Any] = List(1:Int, 2.0:Double, "3":String)
    val t: (Int,Double,String) = xs.foldLeft((Tuple3[Int,Double,String] _).curried:Any)({
      case (f,x) => f.asInstanceOf[Any=>Any](x)
    }).asInstanceOf[(Int,Double,String)]
    

1

जहाँ तक आपके पास प्रकार है:

val x: List[Int] = List(1, 2, 3)

def doSomething(a:Int *)

doSomething(x:_*)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.