जवाबों:
इसका उपयोग अनुक्रम समझ में किया जाता है (जैसे पायथन की सूची-समझ और जनरेटर, जहाँ आप भी उपयोग कर सकते हैं 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
संकेतन के बराबर है, और यह कई मोनैडिक ऑपरेशनों की रचना के लिए एक सिंटैक्टिक चीनी से ज्यादा कुछ नहीं है। जैसा कि इस कथन से सबसे ज्यादा मदद मिलेगी कि किसी को भी मदद की ज़रूरत नहीं है, चलो फिर से कोशिश करें ... :-)
स्काला के for
comprehensions नक्शे के साथ कई आपरेशनों की रचना के लिए वाक्यात्मक चीनी है, 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
, जो हमेशा गैर-सख्त होता है, चाहे संग्रह की कठोरता कोई भी हो। निम्न उदाहरण List
Scala 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
व्यवहार करता है। साइड नोट के रूप में, Range
Scala 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), जो अच्छा है
जबकि नक्शा () परिणाम की तरह लौटेगा: सूची (झूठी, झूठी, सच्ची, सच्ची, सच्ची), जो संभवत: वह नहीं है जो आप चाहते हैं।