ฉันเข้าใจผลผลิตของ Ruby และ Python ผลผลิตของสกาลาทำอะไร?
ฉันเข้าใจผลผลิตของ Ruby และ Python ผลผลิตของสกาลาทำอะไร?
คำตอบ:
มันถูกใช้ในการทำความเข้าใจตามลำดับ (เช่น list-comprehensions และ Python ที่คุณอาจใช้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)
}
}
การแสดงออกที่สอดคล้องกันใน F # จะเป็น
[ for a in args -> a.toUpperCase ]
หรือ
from a in args select a.toUpperCase
ใน Linq
ทับทิมyieldมีผลแตกต่างกัน
ฉันคิดว่าคำตอบที่ยอมรับนั้นยอดเยี่ยม แต่ดูเหมือนว่าหลายคนล้มเหลวที่จะเข้าใจประเด็นพื้นฐานบางอย่าง
ประการแรกความforเข้าใจของสกาล่าเทียบเท่ากับของแฮสเคลล์doสัญกรณ์และไม่มีอะไรมากไปกว่าน้ำตาลซินแทกติกสำหรับองค์ประกอบของการปฏิบัติการแบบ monadic หลายอย่าง เนื่องจากข้อความนี้มักจะไม่ช่วยใครก็ตามที่ต้องการความช่วยเหลือลองอีกครั้ง… :-)
Scala ของforcomprehensions เป็นน้ำตาลประโยคสำหรับองค์ประกอบของการดำเนินงานหลายแผนที่, และflatMap หรือfilter foreachสกาล่าจะแปลคำว่าfor-expression เป็นการเรียกไปยังวิธีการเหล่านั้นดังนั้นคลาสใดก็ตามที่ให้พวกมันหรือเซตย่อยของพวกมันสามารถใช้กับความเข้าใจได้
ก่อนอื่นเรามาพูดถึงการแปล มีกฎง่าย ๆ :
นี้
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 {...}
มีการแปลใน Scala 2.7 เป็น
c.filter(x => cond).map(x => {...})
หรือบน Scala 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
withFilterScala 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จะได้รับการพิจารณาตามความต้องการแทนที่จะนำไปใช้กับการเก็บรวบรวมทั้งหมดก่อน
แนะนำ Scala 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...})เป็
ใช่อย่างที่ Earwicker พูดมันเหมือนกับของ LINQ selectและมีส่วนเกี่ยวข้องกับ Ruby และ Python เพียงเล็กน้อยyieldเท่านั้น โดยทั่วไปใน C # คุณจะเขียน
from ... select ???
ในสกาล่าคุณมีแทน
for ... yield ???
สิ่งสำคัญคือต้องเข้าใจว่า - ความเข้าใจforไม่เพียง แต่ทำงานกับลำดับเท่านั้น แต่ด้วยประเภทใด ๆ ที่กำหนดวิธีการบางอย่างเช่น LINQ:
mapมันจะช่วยให้for-expressions ประกอบด้วยเครื่องกำเนิดไฟฟ้าเดียวflatMapเช่นเดียวกับmapมันจะช่วยให้for-expressions ประกอบด้วยเครื่องกำเนิดไฟฟ้าหลายforeachจะอนุญาตให้for-loops โดยไม่มีผลตอบแทน (ทั้งที่มีเครื่องกำเนิดเดี่ยวและหลายเครื่อง)filterจะช่วยให้forการแสดงออก -filter เริ่มต้นด้วยif
ในforการแสดงออกถ้าคุณไม่ได้รับคำตอบที่ดีกว่าจากผู้ใช้ Scala (ซึ่งฉันไม่ใช่) นี่คือความเข้าใจของฉัน
มันจะปรากฏขึ้นเป็นส่วนหนึ่งของการแสดงออกเริ่มต้นด้วยforซึ่งระบุวิธีการสร้างรายการใหม่จากรายการที่มีอยู่
สิ่งที่ต้องการ:
var doubled = for (n <- original) yield n * 2
ดังนั้นจึงมีรายการเอาท์พุทหนึ่งรายการสำหรับแต่ละอินพุต (แม้ว่าฉันเชื่อว่ามีวิธีการทำสำเนาที่ซ้ำกัน)
นี่ค่อนข้างแตกต่างจาก "ความต่อเนื่องที่จำเป็น" ที่เปิดใช้งานโดยผลผลิตในภาษาอื่นซึ่งให้วิธีการสร้างรายการความยาวใด ๆ จากรหัสจำเป็นบางอย่างที่มีโครงสร้างเกือบทุกชนิด
(หากคุณคุ้นเคยกับ C # จะใกล้กับผู้ให้บริการของ LINQ selectมากกว่าที่จะเป็นyield return)
คำหลักyieldใน Scala เป็นเพียงน้ำตาลประโยคซึ่งสามารถแทนที่ได้ง่ายโดย a mapเนื่องจากDaniel Sobral ได้อธิบายรายละเอียดไว้แล้ว
บนมืออื่น ๆ ที่yieldเป็นอย่างที่ทำให้เข้าใจผิดถ้าคุณกำลังมองหาเครื่องกำเนิดไฟฟ้า (หรือต) คล้ายกับผู้ที่อยู่ในหลาม ดูเธรด SO นี้สำหรับข้อมูลเพิ่มเติม: วิธีที่เหมาะสมในการใช้ 'yield' ใน Scala คืออะไร
พิจารณาความเข้าใจต่อไปนี้
val A = for (i <- Int.MinValue to Int.MaxValue; if i > 3) yield i
มันอาจจะเป็นประโยชน์ในการอ่านออกเสียงดังต่อไปนี้
" สำหรับแต่ละจำนวนเต็มi, ถ้ามันเป็นมากกว่า3นั้นผลผลิต (การผลิต) iและเพิ่มเข้าไปในรายการA".
ในแง่ของสัญกรณ์ set-builderคณิตศาสตร์ข้างต้นสำหรับความเข้าใจนั้นคล้ายคลึงกับ
ซึ่งอาจจะอ่านว่า
" สำหรับแต่ละจำนวนเต็ม, ถ้ามันเป็นมากกว่า
นั้นก็เป็นสมาชิกคนหนึ่งของชุด
."
หรืออีกวิธีหนึ่งคือ
" คือชุดของจำนวนเต็มทั้งหมด
ซึ่งแต่ละชุด
มีค่ามากกว่า
"
Yield นั้นคล้ายกับลูปที่มีบัฟเฟอร์ซึ่งเราไม่สามารถมองเห็นและสำหรับการเพิ่มทีละแต่ละมันยังคงเพิ่มรายการถัดไปในบัฟเฟอร์ เมื่อการวนรอบสำหรับเสร็จสิ้นการทำงานก็จะส่งกลับคอลเลกชันของค่าที่ได้ทั้งหมด Yield สามารถใช้เป็นตัวดำเนินการทางคณิตศาสตร์อย่างง่ายหรือแม้แต่ใช้ร่วมกับอาร์เรย์ ต่อไปนี้เป็นสองตัวอย่างง่ายๆเพื่อความเข้าใจที่ดีขึ้นของคุณ
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 [(Int, Char)] = รายการ ((1, a), (1, b), (1, c), (2, a), (2, b), (2, c), ( 3, a), (3, b), (3, c))
หวังว่านี่จะช่วยได้ !!
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) ซึ่งเป็นสิ่งที่ดี
ในขณะที่ map () จะแสดงผลลัพธ์ดังนี้: รายการ (false, false, true, true, true) ซึ่งอาจไม่ใช่สิ่งที่คุณตั้งใจ