Python Comprehension (List / Dict)
เวลาเราสร้างลิสต์ใหม่จากลิสต์เดิม โค้ดมักจะออกมาหน้าตาแบบนี้: สร้างลิสต์ว่าง วนลูป แล้ว append ทีละตัว Comprehension คือวิธีเขียนงานแบบนั้นให้จบในบรรทัดเดียว ซึ่งเป็นสำนวนที่เจอทั่วไปในโค้ด Python
List Comprehension
เทียบให้เห็นภาพ โค้ดแบบเดิม:
squares = []
for i in range(1, 6):
squares.append(i ** 2)
print(squares) # [1, 4, 9, 16, 25]เขียนด้วย comprehension:
squares = [i ** 2 for i in range(1, 6)]
print(squares) # [1, 4, 9, 16, 25]อ่านจากซ้ายไปขวาว่า “เอา i ** 2 สำหรับแต่ละ i ใน range(1, 6)” โครงคือ:
[ นิพจน์ for ตัวแปร in ลำดับข้อมูล ]ตัวอย่างเพิ่มเติม
names = ["สมชาย", "สมหญิง", "สมศรี"]
upper = [n.upper() for n in names]
lengths = [len(n) for n in names]
celsius = [0, 20, 37, 100]
fahrenheit =
print(fahrenheit) # [32.0, 68.0, 98.6, 212.0]ใส่เงื่อนไขกรอง
เติม if ต่อท้าย เพื่อเลือกเฉพาะสมาชิกที่ผ่านเงื่อนไข
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in numbers if n % 2 == 0]
print(evens) # [2, 4, 6, 8, 10]
big = [n for n in numbers if n > 5]
print(big) # [6, 7, 8, 9, 10]โครงตอนมีเงื่อนไข:
[ นิพจน์ for ตัวแปร in ลำดับข้อมูล if เงื่อนไข ]กรองข้อมูลจริง
students = [
{"name": "สมชาย", "score": 85},
{"name": "สมหญิง", "score": 45},
{"name": "สมศรี", "score": 92},
]
passed = [s["name"] for s in students if s["score"] >= 50]
print(passed) # ['สมชาย', 'สมศรี']if/else ใน comprehension
ถ้าอยากได้ค่าต่างกันตามเงื่อนไข (ไม่ใช่กรองทิ้ง) ให้เอา if/else ไปไว้ หน้า for
numbers = [1, 2, 3, 4, 5, 6]
labels = ["คู่" if n % 2 == 0 else "คี่" for n in numbers]
print(labels) # ['คี่', 'คู่', 'คี่', 'คู่', 'คี่', 'คู่']สังเกตความต่าง:
[x for x in data if cond]— กรอง เอาเฉพาะที่ผ่าน (ifอยู่ท้าย)[a if cond else b for x in data]— แปลงค่า เก็บทุกตัว (if/elseอยู่หน้า)
Dict Comprehension
หลักการเดียวกัน แต่ผลลัพธ์เป็นดิกชันนารี เขียนคู่ คีย์: ค่า หน้า for
words = ["python", "code", "data"]
lengths = {w: len(w) for w in words}
print(lengths) # {'python': 6, 'code': 4, 'data': 4}สลับคีย์กับค่า
prices = {"กาแฟ": 45, "ชา": 40}
flipped = {price: name for name, price in prices.items()}
print(flipped) # {45: 'กาแฟ', 40: 'ชา'}กรองดิกชันนารี
scores = {"สมชาย": 85, "สมหญิง": 45, "สมศรี": 92}
passed = {name: s for name, s in scores.items() if s >= 50}
print(passed) # {'สมชาย': 85, 'สมศรี': 92}Set Comprehension
มีด้วย ใช้ปีกกาแต่ไม่มีคู่คีย์–ค่า ผลลัพธ์เป็นเซ็ต (ค่าไม่ซ้ำ)
text = "abracadabra"
unique_letters = {ch for ch in text}
print(unique_letters) # {'a', 'b', 'r', 'c', 'd'}อย่าใช้เกินพอดี
Comprehension เหมาะกับงานที่ตรรกะสั้น ๆ ถ้าเงื่อนไขซับซ้อน มีหลายชั้น หรือต้องทำอะไรหลายบรรทัดต่อรอบ ให้กลับไปเขียน for ธรรมดาจะอ่านง่ายกว่า เป้าหมายคือโค้ดที่คนอ่านเข้าใจ ไม่ใช่โค้ดที่สั้นที่สุด
# แบบนี้ยัดเยียดเกินไป อ่านยาก
result = [x * 2 if x > 0 else x * -1 for sub in matrix for x in sub if x != 0]
# เขียน for ธรรมดาดีกว่าตัวอย่างรวม: จัดข้อมูลจากไฟล์ CSV จำลอง
raw = "สมชาย,85\nสมหญิง,45\nสมศรี,92\nสมพงษ์,78"
lines = raw.split("\n")
# แปลงเป็นลิสต์ของทูเพิล (ชื่อ, คะแนน)
records = [(line.split(",")[0], int(line.split(",")[1])) for line in lines]
print(records)
# [('สมชาย', 85), ('สมหญิง', 45), ('สมศรี', 92), ('สมพงษ์', 78)]
# เอาเฉพาะคนที่ผ่าน เก็บเป็น dict
passed = {name: score for name, score in records if score >= 50}
print(passed)
# {'สมชาย': 85, 'สมศรี': 92, 'สมพงษ์': 78}
# ค่าเฉลี่ยของคนที่ผ่าน
avg = sum(passed.values()) / len(passed)
print(f"เฉลี่ยคนที่ผ่าน: {avg:.2f}") # เฉลี่ยคนที่ผ่าน: 85.00เช็คความเข้าใจก่อนข้ามบท
- แปลงลูปง่าย ๆ ให้เป็น list comprehension ได้
- ใส่เงื่อนไขกรองข้อมูลใน comprehension ได้โดยยังอ่านรู้เรื่อง
- บอกได้ว่าเมื่อ comprehension เริ่มซ้อนหรือยาวเกินไป ควรกลับไปใช้
forธรรมดา
สรุป
- List comprehension:
[นิพจน์ for x in data]แทนการวน append - เติม
ifท้ายเพื่อกรอง, เอาif/elseไว้หน้า for เพื่อแปลงค่า - Dict comprehension:
{k: v for ... }และ set comprehension:{x for ...} - ถ้าตรรกะเริ่มซับซ้อน กลับไปใช้ for ธรรมดา อ่านง่ายกว่า
บทถัดไปปิดท้ายช่วงโครงสร้างข้อมูลด้วยเรื่อง Slicing และ Indexing แบบเจาะลึก