ลูป for ใน Python: วนซ้ำได้ทุกอย่าง พร้อมตัวอย่าง
บทเรียนนี้แปลจากต้นฉบับภาษาอังกฤษRead in EnglishLeer en españolЧитать на русскомLer em portuguêsแจ้งข้อผิดพลาดในการแปล
ลองนึกภาพว่าคุณเป็นครูที่มีนักเรียน 30 คน และต้องพิมพ์สมุดพกให้ทุกคน คุณจะเขียนคำสั่ง print แยกกัน 30 คำสั่งไหม ไม่แน่นอน คุณจะบอกคอมพิวเตอร์ว่า "สำหรับนักเรียนแต่ละคน ให้พิมพ์สมุดพกของคนนั้น" นั่นคือสิ่งที่ลูป for ทำ
ในบทเรียนนี้ คุณจะได้เรียนวิธีใช้ลูป for ของ Python เพื่อทำงานซ้ำกับลิสต์ (list) สตริง ช่วงของตัวเลข และดิกชันนารี (dictionary) และจะได้รู้จักเครื่องมือทรงพลังอย่าง enumerate() และ zip() ที่ทำให้การวนลูปง่ายขึ้นอีก
เมื่อจบบทเรียน คุณจะประมวลผลกลุ่มข้อมูลได้อย่างมีประสิทธิภาพ แทนการเขียนโค้ดซ้ำๆ นี่เป็นหนึ่งในทักษะที่สำคัญที่สุดของการเขียนโปรแกรม
ลูป for ใน Python ทำงานอย่างไร
ลูป for รับกลุ่มของข้อมูล แล้วรันโค้ดชุดเดิมหนึ่งครั้งต่อข้อมูลแต่ละตัว ในแต่ละรอบของลูป จะมีตัวแปรตัวหนึ่งเก็บข้อมูลตัวปัจจุบันไว้ Python เรียกแต่ละรอบว่า การวนซ้ำ (iteration)
ลองนึกถึงการแจกไพ่ คุณหยิบสำรับไพ่ขึ้นมา แล้ววางไพ่ทีละใบหงายหน้าลงบนโต๊ะ ไพ่เปลี่ยนไปทุกครั้ง แต่สิ่งที่ทำยังเหมือนเดิม
apple banana cherry
โครงสร้างเป็นแบบนี้: คีย์เวิร์ด for ชื่อตัวแปร (fruit) คีย์เวิร์ด in และกลุ่มข้อมูล (fruits) ตามด้วยเครื่องหมายโคลอน โค้ดที่เยื้องอยู่ด้านล่างจะรันหนึ่งครั้งต่อสมาชิกแต่ละตัวในลิสต์
ในรอบแรก fruit มีค่าเป็น "apple" รอบที่สองเป็น "banana" รอบที่สามเป็น "cherry" หลังจากสมาชิกตัวสุดท้าย ลูปจะจบ และ Python จะทำงานในส่วนถัดไปต่อ
Added 10, total is now 10 Added 20, total is now 30 Added 30, total is now 60 Added 40, total is now 100 Final total: 100
รูปแบบที่เริ่มจากค่าหนึ่งแล้วปรับค่านั้นในทุกรอบ เรียกว่า การสะสมค่า (accumulation) คุณจะได้ใช้รูปแบบนี้ตลอดเวลา เช่น หาผลรวมของตัวเลข ต่อสตริง เก็บผลลัพธ์ และอีกมากมาย
range() ใน Python ทำอะไร
บางครั้งคุณไม่มีลิสต์ให้วนลูป แค่อยากทำบางอย่างซ้ำตามจำนวนครั้งที่กำหนด หรือวนไปตามลำดับตัวเลข นั่นคือหน้าที่ของ range()
range() สร้างลำดับของตัวเลข แต่ไม่ได้สร้างลิสต์ไว้ในหน่วยความจำ มันผลิตตัวเลขออกมาทีละตัวตามที่ลูปต้องการ จึงทำงานได้อย่างมีประสิทธิภาพแม้ช่วงตัวเลขจะใหญ่มาก
0 1 2 3 4
สังเกตว่า range(5) เริ่มที่ 0 และหยุดก่อนถึง 5 ได้ตัวเลขมา 5 ตัวพอดี คือ 0 ถึง 4 รูปแบบ "เริ่มที่ศูนย์ หยุดก่อนถึงค่าสุดท้าย" นี้ใช้เหมือนกันทั่วทั้ง Python
1 2 3 4 5
เมื่อมีสองอาร์กิวเมนต์ ตัวแรกคือจุดเริ่มต้น ตัวที่สองคือจุดหยุด (ไม่รวมค่านั้น) ดังนั้น range(1, 6) จะให้ 1, 2, 3, 4, 5
Count by 2s: 0 2 4 6 8 10 Countdown: 5 4 3 2 1 Blastoff!
อาร์กิวเมนต์ตัวที่สามคือ step (ระยะก้าว) ซึ่งบอกว่าจะบวกเพิ่มทีละเท่าไร step เท่ากับ 2 จะได้ตัวเลขแบบเว้นตัว step ที่ติดลบจะนับถอยหลัง คุณใช้ step เป็นจำนวนเต็มใดก็ได้ ทั้งบวกและลบ
วนลูปผ่านสตริงและดิกชันนารีได้อย่างไร
ลูป for ใช้ได้กับทุกอย่างใน Python ที่เป็น ออบเจกต์ที่วนซ้ำได้ (iterable) ไม่ใช่แค่ลิสต์และ range สตริงและดิกชันนารีคือ iterable สองแบบที่คุณจะวนลูปบ่อยที่สุด
วนลูปผ่านสตริง
เมื่อวนลูปผ่านสตริง คุณจะได้อักขระมาทีละตัว ซึ่งมีประโยชน์สำหรับการนับตัวอักษร ตรวจการสะกดคำ หรือประมวลผลข้อความทีละอักขระ
P y t h o n
แต่ละรอบจะได้อักขระตัวถัดไป end=" " ในฟังก์ชัน print จะแทนที่การขึ้นบรรทัดใหม่ (ค่าเริ่มต้น) ด้วยช่องว่าง อักขระทั้งหมดจึงแสดงอยู่ในบรรทัดเดียว
"programming" has 3 vowels
ตัวอย่างนี้ใช้ลูป for ร่วมกับคำสั่ง if สำหรับอักขระแต่ละตัว เราตรวจว่าเป็นสระหรือไม่ ถ้าใช่ ก็เพิ่มค่าตัวนับ นี่เป็นรูปแบบที่คุณจะได้เขียนอยู่เสมอ
วนลูปผ่านดิกชันนารี
เมื่อวนลูปผ่านดิกชันนารี โดยค่าเริ่มต้นคุณจะได้ คีย์ (key) ถ้าต้องการทั้งคีย์และค่า ให้ใช้เมธอด .items()
Students: Alice Bob Charlie Report card: Alice: 92 Bob: 85 Charlie: 78
เมธอด .items() คืนแต่ละรายการออกมาเป็นคู่ (คีย์, ค่า) การเขียน for name, score in scores.items() คือการ แยกค่า (unpack) แต่ละคู่ออกเป็นตัวแปรสองตัว ซึ่งอ่านง่ายกว่าการเข้าถึง scores[name] ภายในลูป
enumerate() ใน Python ทำอะไร
บางครั้งคุณต้องการทั้งสมาชิกและตำแหน่งของมันในลิสต์ คุณอาจใช้ range(len(list)) แล้วเข้าถึงลิสต์ด้วยดัชนีเอง แต่ Python มีวิธีที่สะอาดกว่า นั่นคือ enumerate()
colors = ["red", "green", "blue"]
for i in range(len(colors)):
print(f"{i}: {colors[i]}")colors = ["red", "green", "blue"]
for i, color in enumerate(colors):
print(f"{i}: {color}")enumerate() ครอบออบเจกต์ที่วนซ้ำได้ แล้วให้ผลเป็นคู่ (ดัชนี, สมาชิก) คุณแยกแต่ละคู่ออกเป็นตัวแปรสองตัว ทั้งสองตัวอย่างให้ผลลัพธ์เหมือนกัน แต่แบบที่ใช้ enumerate() อ่านง่ายกว่าและเป็นสไตล์ Python (Pythonic) มากกว่า
Today's to-do list: 1. Buy groceries 2. Clean house 3. Walk dog 4. Cook dinner
อาร์กิวเมนต์ start=1 บอกให้ enumerate() เริ่มนับจาก 1 แทน 0 เหมาะมากสำหรับสร้างรายการที่มีเลขลำดับ ซึ่ง "รายการที่ 0" ไม่มีความหมายสำหรับผู้ใช้
zip() ช่วยวนลูปหลายลิสต์พร้อมกันได้อย่างไร
ถ้าคุณมีสองลิสต์ที่สัมพันธ์กันและต้องการประมวลผลไปพร้อมกันล่ะ เช่น ลิสต์ชื่อนักเรียนกับลิสต์คะแนนของแต่ละคน zip() จะจับคู่ข้อมูลให้ คุณจึงวนลูปผ่านทั้งสองลิสต์ได้ในคราวเดียว
Alice: 92 (Pass) Bob: 85 (Pass) Charlie: 78 (Needs improvement)
zip() รับออบเจกต์ที่วนซ้ำได้ตั้งแต่สองตัวขึ้นไป แล้วรวมเข้าด้วยกันทีละสมาชิก ในรอบแรก คุณจะได้สมาชิกตัวแรกจากแต่ละลิสต์ ในรอบที่สอง ได้สมาชิกตัวที่สองจากแต่ละลิสต์ แบบนี้ไปเรื่อยๆ
Alice Smith, age 25 Bob Jones, age 30 Charlie Brown, age 22
ลูป for ซ้อนกันคืออะไร
คุณใส่ลูป for ไว้ข้างในลูป for อีกตัวได้ ลูปด้านในจะทำงานจนครบทุกรอบ ในแต่ละรอบของลูปด้านนอก เรียกว่า การซ้อนลูป (nesting) และเป็นวิธีที่ใช้ทำงานกับกริด ตาราง และการจับคู่แบบต่างๆ
1 x 1 = 1 1 x 2 = 2 1 x 3 = 3 2 x 1 = 2 2 x 2 = 4 2 x 3 = 6 3 x 1 = 3 3 x 2 = 6 3 x 3 = 9
เมื่อ row เป็น 1 ลูปด้านในจะทำงานโดย col มีค่า 1, 2, 3 จากนั้น row เปลี่ยนเป็น 2 แล้วลูปด้านในก็ทำงานอีกครั้งโดย col มีค่า 1, 2, 3 ลูปด้านในจะเริ่มใหม่ทุกครั้งที่ลูปด้านนอกขยับไปรอบถัดไป
แบบฝึกหัด
ถึงเวลาใช้ทักษะลูป for ของคุณแล้ว แบบฝึกหัดเหล่านี้ไล่ระดับจากการวนลูปพื้นฐาน ไปจนถึงการใช้ลูปร่วมกับเครื่องมือที่คุณเพิ่งเรียนมา
ลองทำแต่ละข้อด้วยตัวเองก่อนดูคำใบ้ การติดแล้วหาทางออกได้เองคือวิธีสร้างทักษะที่แท้จริง
มีลิสต์รายการของชำให้มา ใช้ลูป for แสดงของแต่ละรายการ บรรทัดละหนึ่งรายการ
ผลลัพธ์ที่ควรได้:
milk
eggs
bread
butterใช้ range() และลูป for คำนวณผลรวมของตัวเลขทั้งหมดตั้งแต่ 1 ถึง 10 (รวม 10 ด้วย) แล้วแสดงผลลัพธ์
ผลลัพธ์ที่ควรได้:
Sum: 55ทายให้ตรงทุกตัวอักษรว่าโค้ดจะแสดงอะไร โดยยังไม่ต้องรัน สังเกตอาร์กิวเมนต์ของ range() และเงื่อนไข if ให้ดี
จากนั้นรันเพื่อตรวจคำตอบ
โค้ดนี้ควรนับว่าตัวอักษร "l" ปรากฏในข้อความ "hello world" กี่ครั้ง แต่มีบั๊กอยู่ แก้โค้ดให้แสดงผล:
The letter "l" appears 3 timesห้ามแก้ตัวแปร word หรือคำสั่ง print บรรทัดสุดท้าย ให้แก้เฉพาะตรรกะของลูป
ใช้ enumerate() กับ start=1 เพื่อแสดงเมนูร้านอาหารแบบมีเลขลำดับ
ผลลัพธ์ที่ควรได้:
1. Burger - $8.99
2. Pizza - $12.50
3. Salad - $7.25
4. Pasta - $10.00ใช้ลูป for กลับลำดับสตริง "Python" โดยสร้างสตริงใหม่ทีละอักขระ ห้ามใช้การตัดช่วง ([::-1]) หรือฟังก์ชัน reversed()
ผลลัพธ์ที่ควรได้:
nohtyPวนลูปผ่านดิกชันนารี grades แล้วแสดงชื่อนักเรียนแต่ละคนพร้อมเกรดตัวอักษร คะแนน 90 ขึ้นไปได้ "A" 80 ขึ้นไปได้ "B" 70 ขึ้นไปได้ "C" และต่ำกว่า 70 ได้ "F"
ผลลัพธ์ที่ควรได้:
Alice: 95 (A)
Bob: 82 (B)
Charlie: 67 (F)
Diana: 73 (C)สรุป: ลูป for ใน Python
นี่คือทุกอย่างที่คุณได้เรียนเกี่ยวกับลูป for:
| รูปแบบ | ทำอะไร | ตัวอย่าง |
|---|---|---|
for x in list | วนลูปผ่านสมาชิกแต่ละตัว | for fruit in fruits: |
for i in range(n) | วนลูป n ครั้ง (0 ถึง n-1) | for i in range(5): |
range(start, stop, step) | ลำดับตัวเลขที่กำหนดเอง | range(1, 11, 2) |
for char in string | วนลูปผ่านอักขระ | for c in "hello": |
for k, v in dict.items() | วนลูปผ่านคู่คีย์-ค่า | for name, score in grades.items(): |
enumerate(iterable) | ได้ทั้งดัชนีและสมาชิก | for i, x in enumerate(list): |
zip(a, b) | จับคู่สมาชิกจากสองลิสต์ | for x, y in zip(names, scores): |
กฎสำคัญที่ควรจำ:
for ลงท้ายด้วยโคลอน (:)range() หยุดก่อนถึงค่าสุดท้ายenumerate() ดีกว่า range(len(...))zip() หยุดที่ลิสต์ที่สั้นที่สุดfor student in students)เรียนอะไรต่อ
ลูป for เหมาะเมื่อคุณรู้แน่ชัดว่าจะวนลูปผ่านอะไร แต่ถ้าคุณอยากวนลูปไปเรื่อยๆ จนกว่าเงื่อนไขบางอย่างจะเปลี่ยนล่ะ นั่นคือหน้าที่ของ ลูป while ในบทเรียนถัดไป ลูป while ใน Python คุณจะได้เรียนการวนลูปตามเงื่อนไขแทนการวนตามกลุ่มข้อมูล