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 แบบเจาะลึก