เซตใน Python: ข้อมูลไม่ซ้ำ การดำเนินการ และการใช้งานจริง
บทเรียนนี้แปลจากต้นฉบับภาษาอังกฤษRead in EnglishLeer en españolЧитать на русскомLer em portuguêsแจ้งข้อผิดพลาดในการแปล
ลองนึกว่าคุณเป็นครูที่กำลังเช็กชื่อ นักเรียนคนหนึ่งเผลอเซ็นชื่อในใบเช็กชื่อสองครั้ง แปลว่าเขาเข้าเรียนสองครั้งหรือเปล่า แน่นอนว่าไม่ใช่ สิ่งที่คุณสนใจคือ ใคร มาเรียนบ้าง ไม่ใช่ว่าเขาเขียนชื่อไว้กี่ครั้ง
เซตใน Python (set) ทำงานแบบเดียวกัน เซตคือชุดข้อมูลที่ลบข้อมูลซ้ำออกให้เองโดยอัตโนมัติ สมาชิกทุกตัวในเซตไม่ซ้ำกัน และเซตไม่สนใจลำดับ สิ่งที่เซตสนใจคือ การเป็นสมาชิก เท่านั้น
ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีสร้างเซต ใช้การดำเนินการที่ทรงพลังอย่างยูเนียนและอินเตอร์เซกชัน แก้ไขเซตด้วยเมธอด และรู้ว่าเมื่อไรเซตคือเครื่องมือที่เหมาะกับงานที่สุด
วิธีสร้างเซตใน Python
คุณสร้างเซตได้โดยใส่สมาชิกไว้ใน วงเล็บปีกกา {} คั่นด้วยเครื่องหมายจุลภาค ถ้าใส่ค่าซ้ำเข้าไป Python จะข้ามค่าเหล่านั้นไปเงียบ ๆ
{'apple', 'banana', 'cherry'}
{'red', 'green', 'blue'}สังเกตว่าลำดับในผลลัพธ์อาจดูต่างจากที่คุณพิมพ์ไว้ เพราะเซต ไม่มีลำดับ (unordered) Python จึงจัดเก็บสมาชิกภายในแบบใดก็ได้ อย่าพึ่งเซตในการรักษาลำดับที่เจาะจง
คุณยังสร้างเซตจากลิสต์ได้ด้วยคอนสตรัคเตอร์ set() นี่เป็นวิธียอดนิยมในการลบข้อมูลซ้ำออกจากลิสต์
{'Bob', 'Alice', 'Charlie'}
{'o', 'l', 'e', 'h'}การดำเนินการของเซต: ยูเนียน อินเตอร์เซกชัน และผลต่าง
พลังที่แท้จริงของเซตมาจาก การดำเนินการของเซต (set operations) ซึ่งใช้รวม เปรียบเทียบ และหาความต่างระหว่างเซต ลองนึกถึงแผนภาพเวนน์ในวิชาคณิตศาสตร์
ยูเนียน: รวมทุกอย่างเข้าด้วยกัน
ยูเนียน (union) ให้สมาชิกทั้งหมดจากทั้งสองเซตโดยไม่มีตัวซ้ำ ใช้ตัวดำเนินการ | หรือเมธอด .union() ก็ได้
{'Charlie', 'Bob', 'Alice', 'Diana'}
{'Charlie', 'Bob', 'Alice', 'Diana'}อินเตอร์เซกชัน: หาสิ่งที่มีร่วมกัน
อินเตอร์เซกชัน (intersection) ให้เฉพาะสมาชิกที่อยู่ใน ทั้งสอง เซต ใช้ตัวดำเนินการ & หรือ .intersection()
{'Bob', 'Charlie'}ผลต่าง: สิ่งที่มีเฉพาะในเซตเดียว
ผลต่าง (difference) ให้สมาชิกที่อยู่ในเซตแรกแต่ ไม่อยู่ ในเซตที่สอง ใช้ตัวดำเนินการ - หรือ .difference() ในกรณีนี้ลำดับของเซตมีผล
{'Alice'}
{'Diana'}ผลต่างสมมาตร: อยู่ในเซตใดเซตหนึ่ง แต่ไม่อยู่ในทั้งสองเซต
ผลต่างสมมาตร (symmetric difference) ให้สมาชิกที่อยู่ในเซต ใดเซตหนึ่ง แต่ ไม่อยู่ในทั้งสองเซต มองได้ว่าเป็นสิ่งตรงข้ามกับอินเตอร์เซกชัน ใช้ตัวดำเนินการ ^ หรือ .symmetric_difference()
{'Alice', 'Diana'}วิธีเพิ่มและลบสมาชิกในเซต
เซต เปลี่ยนแปลงได้ (mutable) หมายความว่าคุณเพิ่มและลบสมาชิกได้หลังสร้างเซตแล้ว นี่คือเมธอดหลัก ๆ ที่คุณจะได้ใช้
{'apple', 'banana', 'cherry'}
{'date', 'elderberry', 'apple', 'banana', 'cherry'}
{'date', 'elderberry', 'apple', 'cherry'}
{'date', 'elderberry', 'apple', 'cherry'}คุณยังล้างสมาชิกทั้งหมด หรือดึงสมาชิกตัวใดตัวหนึ่งออกจากเซตได้ด้วย (โดยเลือกเองไม่ได้ว่าจะได้ตัวไหน)
Removed: 50
Remaining: {20, 40, 10, 30}
set()ทำไมเซตจึงตรวจสอบการเป็นสมาชิกได้เร็วมาก
เหตุผลดี ๆ ข้อหนึ่งที่ควรใช้เซตคือ การตรวจว่ามีบางสิ่งอยู่หรือไม่ คีย์เวิร์ด in ใช้ได้ทั้งกับลิสต์และเซต แต่เซตเร็วกว่า มาก
bob is allowed! eve is not on the list.
Frozenset คืออะไร
frozenset คือเซตแบบเปลี่ยนแปลงไม่ได้ (immutable) เมื่อสร้างแล้วจะเพิ่มหรือลบสมาชิกไม่ได้ ทำให้ frozenset แฮชได้ (hashable) หมายความว่าใช้เป็นคีย์ของดิกชันนารีหรือเก็บไว้ในเซตอื่นได้
frozenset({'u', 'o', 'i', 'e', 'a'})
frozenset({'u', 'o', 'i', 'f', 'g', 'd', 'e', 'b', 'c', 'a'})เมื่อไรควรใช้เซตแทนลิสต์
เซตกับลิสต์แก้ปัญหาต่างกัน หลักง่าย ๆ คือ ถ้าคุณสนใจ ลำดับ หรือต้องเก็บ ข้อมูลซ้ำ ให้ใช้ลิสต์ ถ้าคุณสนใจ ความไม่ซ้ำ หรือ การค้นหาที่รวดเร็ว ให้ใช้เซต
# Order matters
playlist = ['song1', 'song2', 'song3']
# Duplicates are meaningful
die_rolls = [3, 5, 3, 2, 5, 6]
# You need index access
first = playlist[0]# Only unique items matter
tags = {'python', 'coding', 'tutorial'}
# Fast membership checks
if 'python' in tags:
print('Found!')
# Removing duplicates
unique = set([1, 2, 2, 3, 3])แบบฝึกหัด
คุณมีลิสต์ของอีเมลที่บางอีเมลซ้ำกันมากกว่าหนึ่งครั้ง สร้างเซตชื่อ unique_emails จากลิสต์ emails แล้วแสดงผลโดยเรียงตามตัวอักษรด้วย sorted()
โค้ดนี้แสดงผลอะไร คิดให้ดีว่าเซตจัดการกับข้อมูลซ้ำอย่างไร และฟังก์ชัน len() คืนค่าอะไร
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = set(data)
print(len(unique))เขียนคำสั่ง print() ที่ให้ผลลัพธ์ตรงทุกตัวอักษร
คุณมีเซตสองเซต คือ math และ english หาและแสดงรายชื่อนักเรียนที่ลงทะเบียนเรียน ทั้งสอง วิชา แสดงผลเป็นลิสต์ที่เรียงลำดับแล้ว
โค้ดนี้พยายามสร้างเซตว่าง เพิ่มสมาชิกเข้าไป แล้วแสดงผลลัพธ์ แต่มีบั๊ก เพราะคนเขียนใช้ {} สร้างเซตว่าง แก้บั๊กให้โค้ดทำงานได้ถูกต้อง
คุณมีเซต recipe ที่มีวัตถุดิบทั้งหมดที่สูตรอาหารต้องใช้ และเซต pantry ที่มีของที่คุณมีอยู่แล้ว หาวัตถุดิบที่ยังต้องซื้อเพิ่ม แล้วแสดงผลเป็นลิสต์ที่เรียงลำดับแล้ว
เขียนฟังก์ชันชื่อ dedupe(items) ที่ลบข้อมูลซ้ำออกจากลิสต์โดยรักษาลำดับเดิมไว้ ใช้เซตจดว่าเจอสมาชิกตัวไหนไปแล้วบ้าง แล้วคืนค่าลิสต์ที่ไม่มีข้อมูลซ้ำ
ทดสอบด้วยการเรียก print(dedupe([3, 1, 4, 1, 5, 9, 2, 6, 5, 3]))