สตรีมกับ Views vs Iterators


136

อะไรคือความแตกต่างระหว่าง Streams, Views (SeqView) และ Iterators in scala นี่คือความเข้าใจของฉัน:

  • พวกเขาทั้งหมดเป็นรายการที่ขี้เกียจ
  • สตรีมแคชค่า
  • Iterators สามารถใช้ได้ครั้งเดียวเท่านั้น? คุณไม่สามารถย้อนกลับไปที่จุดเริ่มต้นและประเมินค่าอีกครั้งได้หรือไม่
  • ค่าของมุมมองจะไม่ถูกแคช แต่คุณสามารถประเมินค่าเหล่านั้นซ้ำแล้วซ้ำอีก?

ดังนั้นถ้าฉันต้องการประหยัดพื้นที่ของฮีปฉันควรใช้ตัววนซ้ำ (ถ้าฉันไม่ข้ามรายการอีกครั้ง) หรือมุมมอง? ขอบคุณ


7
ฉันเคยตอบเรื่องนี้มาก่อน แต่จะหาได้อย่างไร? ถอนหายใจ ...
Daniel C. Sobral

คำตอบ:


182

ครั้งแรกที่พวกเขาทั้งหมดที่ไม่เข้มงวด ที่มีความหมายทางคณิตศาสตร์เฉพาะที่เกี่ยวข้องกับฟังก์ชั่น แต่โดยทั่วไปหมายถึงพวกเขาจะคำนวณตามความต้องการแทนล่วงหน้า

Streamเป็นรายการที่ขี้เกียจแน่นอน ในความเป็นจริงในสกาล่าที่Streamเป็นListซึ่งเป็นtail lazy valเมื่อคำนวณแล้วค่าจะยังคงคำนวณและนำมาใช้ใหม่ หรืออย่างที่คุณพูดค่าต่างๆนั้นจะถูกแคชไว้

Iteratorสามารถใช้ได้เพียงครั้งเดียวเพราะมันเป็นตัวชี้ข้าม เข้าไปในคอลเลกชันและไม่คอลเลกชันในตัวเอง สิ่งที่ทำให้พิเศษใน Scala คือความจริงที่ว่าคุณสามารถใช้การแปลงเช่นmapและfilterและเพิ่งได้รับใหม่Iteratorซึ่งจะใช้การแปลงเหล่านี้เมื่อคุณขอองค์ประกอบถัดไป

Scala เคยจัดเตรียมตัววนซ้ำซึ่งสามารถรีเซ็ตได้ แต่มันยากมากที่จะสนับสนุนในลักษณะทั่วไปและพวกเขาไม่ได้ทำรุ่น 2.8.0

มุมมองมีไว้เพื่อให้ดูเหมือนในมุมมองฐานข้อมูล มันเป็นชุดของการเปลี่ยนแปลงที่หนึ่งนำไปใช้กับคอลเลกชันในการผลิตคอลเลกชัน "เสมือน" ดังที่คุณกล่าวการแปลงทั้งหมดจะถูกนำมาใช้ใหม่ทุกครั้งที่คุณต้องการดึงองค์ประกอบจากมัน

ทั้งสองIteratorและมุมมองมีลักษณะหน่วยความจำที่ยอดเยี่ยม Streamเป็นสิ่งที่ดี แต่ใน Scala ประโยชน์หลักของมันคือการเขียนลำดับที่ไม่สิ้นสุด (โดยเฉพาะอย่างยิ่งลำดับที่กำหนดซ้ำ) หนึ่งสามารถหลีกเลี่ยงการเก็บStreamหน่วยความจำทั้งหมดในโดยการทำให้แน่ใจว่าคุณไม่ได้อ้างอิงถึงมันhead(ตัวอย่างเช่นโดยใช้defแทนvalการกำหนดStream)

เนื่องจากบทลงโทษที่เกิดขึ้นจากการดูหนึ่งครั้งจึงควรforceใช้หลังจากการแปลงหรือเก็บไว้เป็นมุมมองหากคาดว่าจะมีองค์ประกอบเพียงไม่กี่ชิ้นเท่านั้นเมื่อเทียบกับขนาดทั้งหมดของมุมมอง


10
Iteratorยังค่อนข้างมีประโยชน์สำหรับการตรวจสอบอนันต์และฉันมักจะชอบพวกเขามากกว่ากระแสที่เป็นไปได้ ประโยชน์ที่แท้จริงในสตรีมคือค่าที่เข้าถึงก่อนหน้านี้จะถูกแคชซึ่งเป็นประโยชน์อย่างยิ่งเมื่อพยายามใช้บางอย่างเช่นลำดับฟีโบนักชีซึ่งกำหนดไว้ในแง่ของค่าก่อนหน้า
Kevin Wright

5
ฟีโบนัชชีเป็นตัวอย่างที่สมบูรณ์แบบน้อยกว่าเพราะมันต้องการเพียงแค่ค่าก่อนหน้า 2 อันสุดท้ายเท่านั้นและการทำให้กระแสทั้งหมดหายไป ฟังก์ชัน Ackermann น่าจะเป็นตัวอย่างที่ยอมรับได้
Jürgen Strobel

4
@ JürgenStrobel Ackermann จะส่งผลให้เกิดประสิทธิภาพการทำงานที่แย่เนื่องจากการเข้าถึงที่จัดทำดัชนีของสตรีมคือ O (n) แต่ฉันเห็นด้วย wrt fibonacci
Daniel C. Sobral

9
โอ้ใช่. สิ่งนี้ทำให้ Stream เป็นตัวเลือกที่แย่สำหรับวิธีการแคชใด ๆ
Jürgen Strobel

7
คำตอบนี้ชัดเจนมากควรเป็นส่วนหนึ่งของเอกสาร ... โอ้จริง ๆ แล้วมันคือ! ขอบคุณ Daniel docs.scala-lang.org/tutorials/FAQ/stream-view-iterator.html
Svend
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.