जवाबों:
इसका उपयोग अनुक्रम समझ में किया जाता है (जैसे पायथन की सूची-समझ और जनरेटर, जहाँ आप भी उपयोग कर सकते हैं 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एक अलग प्रभाव है।
मुझे लगता है कि स्वीकृत उत्तर बहुत अच्छा है, लेकिन ऐसा लगता है कि कई लोग कुछ मूलभूत बिंदुओं को समझने में असफल रहे हैं।
सबसे पहले, स्काला की forसमझ हास्केल के doसंकेतन के बराबर है, और यह कई मोनैडिक ऑपरेशनों की रचना के लिए एक सिंटैक्टिक चीनी से ज्यादा कुछ नहीं है। जैसा कि इस कथन से सबसे ज्यादा मदद मिलेगी कि किसी को भी मदद की ज़रूरत नहीं है, चलो फिर से कोशिश करें ... :-)
स्काला के forcomprehensions नक्शे के साथ कई आपरेशनों की रचना के लिए वाक्यात्मक चीनी है, flatMapऔर filter। या foreach। स्काला वास्तव forमें उन विधियों में कॉल-डेक्प्रेशन का अनुवाद करता है , इसलिए उन्हें प्रदान करने वाला कोई भी वर्ग, या उनका सबसेट, समझ के लिए इस्तेमाल किया जा सकता है।
सबसे पहले, अनुवादों के बारे में बात करते हैं। बहुत सरल नियम हैं:
इस
for(x <- c1; y <- c2; z <-c3) {...}
में अनुवादित है
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))इस
for(x <- c1; y <- c2; z <- c3) yield {...}
में अनुवादित है
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))इस
for(x <- c; if cond) yield {...}
में स्केल 2.7 पर अनुवादित है
c.filter(x => cond).map(x => {...})
या, स्काला 2.8 पर, में
c.withFilter(x => cond).map(x => {...})
पूर्व में एक वापसी के साथ अगर विधि withFilterउपलब्ध नहीं है, लेकिन filterहै। कृपया इस पर अधिक जानकारी के लिए नीचे दिया गया अनुभाग देखें।
इस
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 के बीच गैर-सख्त से सख्त में बदल दिया गया था।
withFilterसख्त संग्रह के लिए भी गैर-सख्त माना जाता है, जो कुछ स्पष्टीकरण के योग्य है। मैं इस पर विचार करूंगा ...
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...})या मुझे कुछ याद आ रहा है?
हाँ, जैसा कि इयरविकर ने कहा, यह LINQ के बराबर है selectऔर रूबी और पायथन के साथ बहुत कम है yield। मूल रूप से, जहां सी # में आप लिखेंगे
from ... select ???
इसके बजाय आपके पास स्काला में
for ... yield ???
यह समझना भी महत्वपूर्ण है कि for-प्रमाण केवल अनुक्रमों के साथ काम नहीं करते हैं, लेकिन किसी भी प्रकार के साथ जो कुछ विधियों को परिभाषित करता है, बस LINQ:
map, तो यह forएकल जनरेटर से -expressions को अनुमति देता है ।flatMapसाथ ही परिभाषित करता है map, तो यह forकई जेनरेटरों से युक्त -expressions की अनुमति देता है ।foreach, तो यह forउपज के बिना -loops (एकल और एकाधिक जनरेटर के साथ) की अनुमति देता है ।filter, यह अनुमति देता है forएक साथ शुरू -Filter भाव if
में forअभिव्यक्ति।जब तक आपको एक स्काला उपयोगकर्ता (जो मैं नहीं हूं) से बेहतर जवाब मिलता है, तो यहां मेरी समझ है।
यह केवल एक शुरुआत के हिस्से के रूप में प्रकट होता है for, जो बताता है कि मौजूदा सूची से नई सूची कैसे उत्पन्न की जाए।
कुछ इस तरह:
var doubled = for (n <- original) yield n * 2
इसलिए प्रत्येक इनपुट के लिए एक आउटपुट आइटम है (हालांकि मेरा मानना है कि डुप्लिकेट को छोड़ने का एक तरीका है)।
यह अन्य भाषाओं में उपज द्वारा सक्षम "अनिवार्य निरंतरता" से काफी अलग है, जहां यह लगभग किसी भी संरचना के साथ कुछ अनिवार्य कोड से किसी भी लंबाई की एक सूची तैयार करने का एक तरीका प्रदान करता है।
(यदि आप C # से परिचित हैं, तो यह LINQ के select ऑपरेटर की तुलना में करीब है yield return)।
yieldस्काला में कीवर्ड केवल सिन्थेटिक चीनी है जिसे आसानी से बदला जा सकता है map, जैसा कि डैनियल सोबरल ने पहले ही विस्तार से बताया है।
दूसरी ओर, yieldबिल्कुल भ्रामक है यदि आप पायथन में उन लोगों के समान जनरेटर (या निरंतरता) की तलाश कर रहे हैं । अधिक जानकारी के लिए यह SO थ्रेड देखें: स्काला में 'उपज' को लागू करने का पसंदीदा तरीका क्या है?
निम्नलिखित -समझ पर विचार करें
val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i
निम्नानुसार इसे ज़ोर से पढ़ने में मदद मिल सकती है
" के लिए प्रत्येक पूर्णांक i, अगर यह से अधिक है 3, तो उपज (उत्पादन) iऔर सूची में जोड़ने के A।"
गणितीय सेट-बिल्डर संकेतन के संदर्भ में , उपरोक्त समझ के अनुरूप है
जो के रूप में पढ़ा जा सकता है
" के लिए प्रत्येक पूर्णांक , अगर यह से अधिक है
, तो यह एक सदस्य है सेट की
।"
या वैकल्पिक रूप से
" सभी पूर्णांकों का सेट है
, जैसे कि प्रत्येक
अधिक से अधिक है
।"
यील्ड लूप के समान है जिसमें एक बफर होता है जिसे हम नहीं देख सकते हैं और प्रत्येक वृद्धि के लिए, यह बफर में अगले आइटम को जोड़ता रहता है। जब लूप के चलने का समय पूरा हो जाता है, तो यह सभी उपज मूल्यों का संग्रह लौटा देता है। यील्ड का उपयोग साधारण अंकगणित ऑपरेटरों या सरणियों के संयोजन में भी किया जा सकता है। आपकी बेहतर समझ के लिए यहां दो सरल उदाहरण दिए गए हैं
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, सी))
उम्मीद है की यह मदद करेगा!!
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 )
कोड के ये दो टुकड़े भी बराबर हैं।
नक्शा उपज के रूप में लचीला है और इसके विपरीत।
उपज नक्शे से अधिक लचीली है (), नीचे उदाहरण देखें
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), जो अच्छा है
जबकि नक्शा () परिणाम की तरह लौटेगा: सूची (झूठी, झूठी, सच्ची, सच्ची, सच्ची), जो संभवत: वह नहीं है जो आप चाहते हैं।