foldLeft และ foldRight
ยุบคอลเลกชันให้เหลือค่าเดียว
foldLeft และ foldRight เป็นบทเรียน Scala for Backend Engineering & Functional Programming ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Scala for Backend Engineering & Functional Programming และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน
การพับคอลเลกชัน
การพับจะยุบคอลเลกชันให้เป็นค่าเดียว โดยรวมสมาชิกเข้ากับตัวสะสมซ้ำ ๆ
รูปแบบตัวสะสมที่คุณเรียนรู้มาคือสิ่งที่ fold สร้างเป็นนามธรรม แทนที่จะเขียนฟังก์ชันช่วยแบบเรียกซ้ำเอง คุณเพียงส่งค่าเริ่มต้นและฟังก์ชันรวมค่าเข้าไป
พื้นฐานของ foldLeft
foldLeft รับตัวสะสมเริ่มต้นและฟังก์ชัน (acc, element) แล้ววนผ่านคอลเลกชันจากซ้ายไปขวา
ในแต่ละขั้นตอน จะนำผลลัพธ์ของฟังก์ชันมาแทนที่ตัวสะสม
val xs = List(1, 2, 3, 4)
val total = xs.foldLeft(0)((acc, x) => acc + x)
@main def run(): Unit =
println(total) // 10การจัดกลุ่มของ foldLeft
foldLeft จัดกลุ่มจากด้านซ้าย สำหรับ List(1, 2, 3) ที่มีค่าเริ่มต้นเป็น z จะคำนวณเป็น f(f(f(z, 1), 2), 3)
ตัวสะสมเป็นอาร์กิวเมนต์ด้านซ้าย จึงสะสมค่าไปขณะเคลื่อนไปทางขวาผ่านลิสต์
// List(1, 2, 3).foldLeft(0)(_ + _)
// = ((0 + 1) + 2) + 3
// = 6พื้นฐานของ foldRight
foldRight ก็รวมสมาชิกเช่นกัน แต่เริ่มจากด้านขวา
ฟังก์ชันของ foldRight รับ (element, acc) โดยให้สมาชิกอยู่ด้านซ้ายและตัวสะสมอยู่ด้านขวา
val xs = List(1, 2, 3, 4)
val total = xs.foldRight(0)((x, acc) => x + acc)
@main def run(): Unit =
println(total) // 10การจัดกลุ่มของ foldRight
foldRight จัดกลุ่มจากด้านขวา สำหรับ List(1, 2, 3) ที่มีค่าเริ่มต้นเป็น z จะคำนวณเป็น f(1, f(2, f(3, z)))
ค่าเริ่มต้นอยู่ทางขวาสุด และลิสต์จะถูกรวมเข้าด้านในจากส่วนท้าย
// List(1, 2, 3).foldRight(0)(_ + _)
// = 1 + (2 + (3 + 0))
// = 6เมื่อทิศทางมีความสำคัญ
สำหรับการดำเนินการที่เปลี่ยนหมู่และสลับที่ได้ เช่น sum หรือผลคูณ การพับทั้งสองแบบจะให้คำตอบเดียวกัน
สำหรับการดำเนินการที่สลับที่ไม่ได้ เช่น การลบหรือการสร้างลิสต์ ทิศทางจะทำให้ผลลัพธ์เปลี่ยนไป จึงควรเลือกอย่างตั้งใจ
val xs = List(1, 2, 3)
val l = xs.foldLeft(0)(_ - _) // ((0-1)-2)-3 = -6
val r = xs.foldRight(0)(_ - _) // 1-(2-(3-0)) = 2
@main def run(): Unit =
println((l, r)) // (-6, 2)การสร้างลิสต์
foldRight เป็นตัวเลือกที่เหมาะตามธรรมชาติสำหรับสร้างลิสต์กลับมาตามลำดับเดิม เพราะทำงานจากส่วนท้ายเข้าด้านใน และการเติมด้านหน้าจะรักษาตำแหน่งของสมาชิก
วิธีนี้จะแปลงสมาชิกแต่ละตัวโดยยังคงลำดับไว้
val xs = List(1, 2, 3)
val doubled = xs.foldRight(List.empty[Int]) { (x, acc) =>
(x * 2) :: acc
}
@main def run(): Unit =
println(doubled) // List(2, 4, 6)foldLeft กลับลำดับ
หากสร้างลิสต์ด้วย foldLeft และเติมสมาชิกด้านหน้า ผลลัพธ์จะกลับลำดับ เพราะสมาชิกถูกเพิ่มจากด้านหน้าเมื่อเคลื่อนไปทางขวา
บางครั้งนี่ก็เป็นผลลัพธ์ที่คุณต้องการพอดี
val xs = List(1, 2, 3)
val rev = xs.foldLeft(List.empty[Int]) { (acc, x) =>
x :: acc
}
@main def run(): Unit =
println(rev) // List(3, 2, 1)ความปลอดภัยของสแตก
foldLeft เป็นการเรียกซ้ำแบบหางและทำงานเป็นลูป จึงปลอดภัยเมื่อใช้กับคอลเลกชันขนาดใหญ่มาก
foldRight กับลิสต์ไม่ใช่การเรียกซ้ำแบบหาง และอาจทำให้สแตกเต็มเมื่อลิสต์ยาวมาก หากไม่จำเป็นต้องเรียงจากขวาไปซ้าย ควรเลือกใช้ foldLeft
// Safe even for millions of elements:
val n = (1 to 1000000).foldLeft(0L)(_ + _)
// foldRight on a long List risks StackOverflowErrorการเปลี่ยนชนิดของผลลัพธ์
ชนิดของตัวสะสมอาจแตกต่างจากชนิดของสมาชิกได้
ในที่นี้ เราพับลิสต์จำนวนเต็มให้เป็นสตริง ดังนั้นค่าเริ่มต้นจึงเป็นสตริงว่าง และแต่ละขั้นตอนจะนำค่ามาต่อท้าย
ชนิดของ fold จะถูกกำหนดโดยค่าเริ่มต้น
val xs = List(1, 2, 3)
val s = xs.foldLeft("")((acc, x) => acc + x.toString)
@main def run(): Unit =
println(s) // "123"Fold ในฐานะเครื่องมือสารพัดประโยชน์
การดำเนินการกับลิสต์จำนวนมากเป็นกรณีเฉพาะของ fold ได้แก่ sum ผลคูณ ความยาว max map filter และ reverse
การมองเห็น fold ที่อยู่เบื้องหลังการดำเนินการเหล่านี้ช่วยให้คุณเขียนโค้ดแบบประกาศที่กระชับ แทนการเขียนการเรียกซ้ำขึ้นเอง
val xs = List(4, 1, 7, 3)
val maxV = xs.foldLeft(Int.MinValue)(_ max _)
val len = xs.foldLeft(0)((acc, _) => acc + 1)
@main def run(): Unit =
println((maxV, len)) // (7, 4)ตรวจสอบความเข้าใจ
วิเคราะห์ทิศทางของ fold และตำแหน่งของค่าเริ่มต้น
สรุปทบทวน
foldLeft เดินจากซ้ายไปขวา โดยมีตัวสะสมอยู่ด้านซ้าย และคำนวณเป็น ((z op a) op b) op c เป็นการเรียกซ้ำแบบหางและปลอดภัยต่อสแตก
foldRight เดินจากขวาไปซ้าย โดยมีค่าเริ่มต้นอยู่ด้านขวา และคำนวณเป็น a op (b op (c op z)) เหมาะสำหรับการสร้างลิสต์โดยรักษาลำดับ แต่สามารถทำให้สแตกเต็มเมื่อลิสต์ยาวมาก
ค่าเริ่มต้นจะกำหนดชนิดของผลลัพธ์ ดังนั้น fold จึงสามารถแปลงคอลเลกชันให้เป็นค่าใด ๆ ได้
คำถามที่พบบ่อย
บทเรียน “foldLeft และ foldRight” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “foldLeft และ foldRight” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Scala for Backend Engineering & Functional Programming ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Scala for Backend Engineering & Functional Programming มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “foldLeft และ foldRight”
ยุบคอลเลกชันให้เหลือค่าเดียว คุณปฏิบัติ Scala for Backend Engineering & Functional Programming ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Scala for Backend Engineering & Functional Programming หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Scala for Backend Engineering & Functional Programming บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “foldLeft และ foldRight” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Scala for Backend Engineering & Functional Programming นี้ได้ไหม
ได้ บทเรียน Scala for Backend Engineering & Functional Programming ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- คิดแบบเรียกซ้ำ
- รูปแบบตัวสะสม
- foldLeft และ foldRight
- reduce และ aggregate