स्काला की पैदावार क्या है?


312

मैं रूबी और पायथन की उपज को समझता हूं। स्काला की पैदावार क्या करती है?

जवाबों:


205

इसका उपयोग अनुक्रम समझ में किया जाता है (जैसे पायथन की सूची-समझ और जनरेटर, जहाँ आप भी उपयोग कर सकते हैं yield)।

इसके संयोजन में लागू किया जाता है forऔर परिणामस्वरूप अनुक्रम में एक नया तत्व लिखता है।

सरल उदाहरण ( scala-lang से )

/** Turn command line arguments to uppercase */
object Main {
  def main(args: Array[String]) {
    val res = for (a <- args) yield a.toUpperCase
    println("Arguments: " + res.toString)
  }
}

एफ # में संबंधित अभिव्यक्ति होगी

[ for a in args -> a.toUpperCase ]

या

from a in args select a.toUpperCase 

Linq में।

रूबी का yieldएक अलग प्रभाव है।


57
तो मैं नक्शे के बजाय उपज का उपयोग क्यों करूंगा? यह मैप कोड बराबर वैल रेस = args.map (_। ToUpperCase) है, है ना?
जियो

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

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

13
कृपया ध्यान दें कि दिया गया उदाहरण मानचित्र की अभिव्यक्ति के बराबर नहीं है: यह समान है। समझ के लिए मैप, फ्लैट मैप और फिल्टर पर कॉल करने के लिए अनुवाद किया जाता है।
डैनियल सी। सोबरल

9
उत्तर इस तरह से शुरू होता है: "इसका उपयोग अनुक्रम समझ में किया जाता है (जैसे पायथन की सूची-समझ और जनरेटर, जहां आप उपज का उपयोग कर सकते हैं)।" यह गलती से किसी को लगता है कि स्काला में पैदावार में पैदावार के समान है। यह मामला नहीं है। पाइथन में, पैदावार को कोरटाइन (या निरंतरता) के संदर्भ में उपयोग किया जाता है, जबकि स्केल में ऐसा नहीं है। अधिक स्पष्टीकरण के लिए, कृपया इस धागे पर जाएं: stackoverflow.com/questions/2201882/…
रिचर्ड गोम्स

817

मुझे लगता है कि स्वीकृत उत्तर बहुत अच्छा है, लेकिन ऐसा लगता है कि कई लोग कुछ मूलभूत बिंदुओं को समझने में असफल रहे हैं।

सबसे पहले, स्काला की forसमझ हास्केल के doसंकेतन के बराबर है, और यह कई मोनैडिक ऑपरेशनों की रचना के लिए एक सिंटैक्टिक चीनी से ज्यादा कुछ नहीं है। जैसा कि इस कथन से सबसे ज्यादा मदद मिलेगी कि किसी को भी मदद की ज़रूरत नहीं है, चलो फिर से कोशिश करें ... :-)

स्काला के forcomprehensions नक्शे के साथ कई आपरेशनों की रचना के लिए वाक्यात्मक चीनी है, flatMapऔर filter। या foreach। स्काला वास्तव forमें उन विधियों में कॉल-डेक्प्रेशन का अनुवाद करता है , इसलिए उन्हें प्रदान करने वाला कोई भी वर्ग, या उनका सबसेट, समझ के लिए इस्तेमाल किया जा सकता है।

सबसे पहले, अनुवादों के बारे में बात करते हैं। बहुत सरल नियम हैं:

  1. इस

    for(x <- c1; y <- c2; z <-c3) {...}

    में अनुवादित है

    c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))
  2. इस

    for(x <- c1; y <- c2; z <- c3) yield {...}

    में अनुवादित है

    c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))
  3. इस

    for(x <- c; if cond) yield {...}

    में स्केल 2.7 पर अनुवादित है

    c.filter(x => cond).map(x => {...})

    या, स्काला 2.8 पर, में

    c.withFilter(x => cond).map(x => {...})

    पूर्व में एक वापसी के साथ अगर विधि withFilterउपलब्ध नहीं है, लेकिन filterहै। कृपया इस पर अधिक जानकारी के लिए नीचे दिया गया अनुभाग देखें।

  4. इस

    for(x <- c; y = ...) yield {...}

    में अनुवादित है

    c.map(x => (x, ...)).map((x,y) => {...})

जब आप बहुत सरल forसमझ को देखते हैं, map/ foreachविकल्प देखते हैं, वास्तव में, बेहतर। एक बार जब आप उन्हें रचना शुरू कर देते हैं, हालांकि, आप आसानी से कोष्ठक और घोंसले के शिकार के स्तर में खो सकते हैं। जब ऐसा होता है, forसमझ आमतौर पर बहुत स्पष्ट है।

मैं एक सरल उदाहरण दिखाता हूँ, और जानबूझकर किसी भी स्पष्टीकरण को छोड़ देता हूँ। आप तय कर सकते हैं कि कौन सा वाक्यविन्यास समझना आसान था।

l.flatMap(sl => sl.filter(el => el > 0).map(el => el.toString.length))

या

for {
  sl <- l
  el <- sl
  if el > 0
} yield el.toString.length

withFilter

स्काला 2.8 ने एक विधि की शुरुआत की withFilter, जिसका मुख्य अंतर यह है कि एक नया, फ़िल्टर्ड, संग्रह वापस करने के बजाय, यह ऑन-डिमांड फ़िल्टर करता है। filterविधि अपने व्यवहार संग्रह की कठोरता के आधार पर परिभाषित किया है। इसे बेहतर समझने के लिए, आइए कुछ Scala 2.7 List(सख्त) और Stream(गैर-सख्त) पर एक नज़र डालें :

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> Stream.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

अंतर होता है क्योंकि filterतुरंत साथ लागू किया जाता है Listबाधाओं की एक सूची लौट रहा, - के बाद से foundहै false। तभी foreachनिष्पादित किया जाता है, लेकिन, इस समय तक, बदलना foundअर्थहीन है, जैसा filterकि पहले ही निष्पादित हो चुका है।

के मामले में Stream, शर्त तुरंत लागू नहीं है। इसके बजाय, जैसा कि प्रत्येक तत्व द्वारा अनुरोध किया गया है foreach, filterस्थिति का परीक्षण करता है, जो foreachइसके माध्यम से प्रभावित करने में सक्षम बनाता है found। बस इसे स्पष्ट करने के लिए, यहाँ समकक्ष-समझ कोड है:

for (x <- List.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

for (x <- Stream.range(1, 10); if x % 2 == 1 && !found) 
  if (x == 5) found = true else println(x)

इससे कई समस्याएं हुईं, क्योंकि लोगों को उम्मीद थी कि ifपहले से पूरे संग्रह पर लागू होने के बजाय, ऑन-डिमांड पर विचार किया जाएगा।

स्काला 2.8 पेश किया withFilter, जो हमेशा गैर-सख्त होता है, चाहे संग्रह की कठोरता कोई भी हो। निम्न उदाहरण ListScala 2.8 पर दोनों विधियों के साथ दिखाता है :

scala> var found = false
found: Boolean = false

scala> List.range(1,10).filter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3
7
9

scala> found = false
found: Boolean = false

scala> List.range(1,10).withFilter(_ % 2 == 1 && !found).foreach(x => if (x == 5) found = true else println(x))
1
3

यह अधिकांश लोगों की अपेक्षा के अनुरूप परिणाम पैदा करता है, बिना बदले कैसे filterव्यवहार करता है। साइड नोट के रूप में, RangeScala 2.7 और Scala 2.8 के बीच गैर-सख्त से सख्त में बदल दिया गया था।


2
Scala 2.8 में एक नया तरीका है। के लिए (x <- c; अगर कंडोम) उपज {...} का अनुवाद c.withFilter (x => cond) में है। scala2.8 में .map (x => {...})।
ईस्टसुन

2
@ इयर्सुन काफी सही है, हालांकि इसमें ऑटोमैटिक फॉलबैक भी है। withFilterसख्त संग्रह के लिए भी गैर-सख्त माना जाता है, जो कुछ स्पष्टीकरण के योग्य है। मैं इस पर विचार करूंगा ...
डैनियल सी। सोबरल

2
@ डैनियल: ओडस्की, एट अल द्वारा "स्कैलांग में प्रोग्रामिंग" में इस विषय का एक बड़ा इलाज है। (मुझे यकीन है कि आप जानते हैं कि पहले से ही)। इसे दिखाने के लिए +1।
राल्फ

पहले 2 अंक सही हैं: 1. for(x <- c; y <- x; z <-y) {...}का अनुवाद c.foreach(x => x.foreach(y => y.foreach(z => {...}))) 2. for(x <- c; y <- x; z <- y) yield {...}में किया गया हैc.flatMap(x => x.flatMap(y => y.map(z => {...})))
डोमिनिक में

क्या यह for(x <- c; y = ...) yield {...}वास्तव में अनुवादित है c.map(x => (x, ...)).map((x,y) => {...})? मुझे लगता है कि इसका अनुवाद किया गया है c.map(x => (x, ...)).map(x => { ...use x._1 and x._2 here...})या मुझे कुछ याद आ रहा है?
प्रोस्टिनिक

23

हाँ, जैसा कि इयरविकर ने कहा, यह LINQ के बराबर है selectऔर रूबी और पायथन के साथ बहुत कम है yield। मूल रूप से, जहां सी # में आप लिखेंगे

from ... select ??? 

इसके बजाय आपके पास स्काला में

for ... yield ???

यह समझना भी महत्वपूर्ण है कि for-प्रमाण केवल अनुक्रमों के साथ काम नहीं करते हैं, लेकिन किसी भी प्रकार के साथ जो कुछ विधियों को परिभाषित करता है, बस LINQ:

  • यदि आपका प्रकार सिर्फ परिभाषित करता है map, तो यह forएकल जनरेटर से -expressions को अनुमति देता है ।
  • यदि यह और flatMapसाथ ही परिभाषित करता है map, तो यह forकई जेनरेटरों से युक्त -expressions की अनुमति देता है ।
  • यदि यह परिभाषित करता है foreach, तो यह forउपज के बिना -loops (एकल और एकाधिक जनरेटर के साथ) की अनुमति देता है ।
  • यदि यह परिभाषित करता है filter, यह अनुमति देता है forएक साथ शुरू -Filter भाव if में forअभिव्यक्ति।

2
@Eldritch Conundrum - जो दिलचस्प रूप से पर्याप्त है वही क्रम जिसमें मूल SQL कल्पना की रूपरेखा है। कहीं न कहीं जिस तरह से SQL भाषा ने ऑर्डर को उलटा किया है, लेकिन यह इस बात का पूरा बोध कराता है कि आप जिस चीज से बाहर निकल रहे हैं, उसके बारे में बताने के लिए आप क्या कर रहे हैं।
जॉर्डन परम

13

जब तक आपको एक स्काला उपयोगकर्ता (जो मैं नहीं हूं) से बेहतर जवाब मिलता है, तो यहां मेरी समझ है।

यह केवल एक शुरुआत के हिस्से के रूप में प्रकट होता है for, जो बताता है कि मौजूदा सूची से नई सूची कैसे उत्पन्न की जाए।

कुछ इस तरह:

var doubled = for (n <- original) yield n * 2

इसलिए प्रत्येक इनपुट के लिए एक आउटपुट आइटम है (हालांकि मेरा मानना ​​है कि डुप्लिकेट को छोड़ने का एक तरीका है)।

यह अन्य भाषाओं में उपज द्वारा सक्षम "अनिवार्य निरंतरता" से काफी अलग है, जहां यह लगभग किसी भी संरचना के साथ कुछ अनिवार्य कोड से किसी भी लंबाई की एक सूची तैयार करने का एक तरीका प्रदान करता है।

(यदि आप C # से परिचित हैं, तो यह LINQ के select ऑपरेटर की तुलना में करीब है yield return)।


1
यह "var दोगुनी होना चाहिए = के लिए (n <- मूल) उपज n * 2"।
रसेल यांग

12

yieldस्काला में कीवर्ड केवल सिन्थेटिक चीनी है जिसे आसानी से बदला जा सकता है map, जैसा कि डैनियल सोबरल ने पहले ही विस्तार से बताया है।

दूसरी ओर, yieldबिल्कुल भ्रामक है यदि आप पायथन में उन लोगों के समान जनरेटर (या निरंतरता) की तलाश कर रहे हैं । अधिक जानकारी के लिए यह SO थ्रेड देखें: स्काला में 'उपज' को लागू करने का पसंदीदा तरीका क्या है?


11

निम्नलिखित -समझ पर विचार करें

val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i

निम्नानुसार इसे ज़ोर से पढ़ने में मदद मिल सकती है

" के लिए प्रत्येक पूर्णांक i, अगर यह से अधिक है 3, तो उपज (उत्पादन) iऔर सूची में जोड़ने के A।"

गणितीय सेट-बिल्डर संकेतन के संदर्भ में , उपरोक्त समझ के अनुरूप है

सेट अंकन

जो के रूप में पढ़ा जा सकता है

" के लिए प्रत्येक पूर्णांक मैं, अगर यह से अधिक है 3, तो यह एक सदस्य है सेट की ए।"

या वैकल्पिक रूप से

" एसभी पूर्णांकों का सेट है मैं, जैसे कि प्रत्येक मैंअधिक से अधिक है 3।"


2

यील्ड लूप के समान है जिसमें एक बफर होता है जिसे हम नहीं देख सकते हैं और प्रत्येक वृद्धि के लिए, यह बफर में अगले आइटम को जोड़ता रहता है। जब लूप के चलने का समय पूरा हो जाता है, तो यह सभी उपज मूल्यों का संग्रह लौटा देता है। यील्ड का उपयोग साधारण अंकगणित ऑपरेटरों या सरणियों के संयोजन में भी किया जा सकता है। आपकी बेहतर समझ के लिए यहां दो सरल उदाहरण दिए गए हैं

scala>for (i <- 1 to 5) yield i * 3

res: scala.collection.immutable.IndexedSeq [Int] = वेक्टर (3, 6, 9, 12, 15)

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

scala> val letters = Seq('a', 'b', 'c')
letters: Seq[Char] = List(a, b, c)

scala> val res = for {
     |     n <- nums
     |     c <- letters
     | } yield (n, c)

Res: Seq [(इंट, चार)] = सूची (१, ए, (१, बी), (१, सी), (२, ए), (२, बी), (२, सी), ( 3, ए), (3, बी), (3, सी))

उम्मीद है की यह मदद करेगा!!


इस प्रश्न का उत्तर देते समय यह पुराना (9 साल पहले) यह इंगित करने में सहायक होता है कि आपका उत्तर पहले से प्रस्तुत सभी अन्य उत्तरों से अलग कैसे है।
jwvh

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

0
val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1
val res4 = aList.filter(_ > 3).map(_ + 1)

println( res3 )
println( res4 )

कोड के ये दो टुकड़े बराबर हैं।

val res3 = for (al <- aList) yield al + 1 > 3
val res4 = aList.map( _+ 1 > 3 )

println( res3 ) 
println( res4 )

कोड के ये दो टुकड़े भी बराबर हैं।

नक्शा उपज के रूप में लचीला है और इसके विपरीत।


-3

उपज नक्शे से अधिक लचीली है (), नीचे उदाहरण देखें

val aList = List( 1,2,3,4,5 )

val res3 = for ( al <- aList if al > 3 ) yield al + 1 
val res4 = aList.map( _+ 1 > 3 ) 

println( res3 )
println( res4 )

उपज प्रिंट परिणाम की तरह होगा: सूची (5, 6), जो अच्छा है

जबकि नक्शा () परिणाम की तरह लौटेगा: सूची (झूठी, झूठी, सच्ची, सच्ची, सच्ची), जो संभवत: वह नहीं है जो आप चाहते हैं।


4
वह तुलना गलत है। आप दो अलग-अलग चीजों की तुलना कर रहे हैं। उपज में अभिव्यक्ति किसी भी तरह से नक्शे में अभिव्यक्ति के समान नहीं है। इसके अलावा, यह बिल्कुल भी नक्शे की तुलना में उपज का "लचीलापन" नहीं दिखाता है।
dotnetN00b
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.