ข้ามไปยังเนื้อหาหลัก
Editor

เซตใน Python: ข้อมูลไม่ซ้ำ การดำเนินการ และการใช้งานจริง

ปานกลาง20 นาที6 แบบฝึกหัด85 XP

บทเรียนนี้แปลจากต้นฉบับภาษาอังกฤษRead in EnglishLeer en españolЧитать на русскомLer em portuguêsแจ้งข้อผิดพลาดในการแปล

0/6 แบบฝึกหัด

ลองนึกว่าคุณเป็นครูที่กำลังเช็กชื่อ นักเรียนคนหนึ่งเผลอเซ็นชื่อในใบเช็กชื่อสองครั้ง แปลว่าเขาเข้าเรียนสองครั้งหรือเปล่า แน่นอนว่าไม่ใช่ สิ่งที่คุณสนใจคือ ใคร มาเรียนบ้าง ไม่ใช่ว่าเขาเขียนชื่อไว้กี่ครั้ง

เซตใน Python (set) ทำงานแบบเดียวกัน เซตคือชุดข้อมูลที่ลบข้อมูลซ้ำออกให้เองโดยอัตโนมัติ สมาชิกทุกตัวในเซตไม่ซ้ำกัน และเซตไม่สนใจลำดับ สิ่งที่เซตสนใจคือ การเป็นสมาชิก เท่านั้น

ในบทเรียนนี้ คุณจะได้เรียนรู้วิธีสร้างเซต ใช้การดำเนินการที่ทรงพลังอย่างยูเนียนและอินเตอร์เซกชัน แก้ไขเซตด้วยเมธอด และรู้ว่าเมื่อไรเซตคือเครื่องมือที่เหมาะกับงานที่สุด

วิธีสร้างเซตใน Python

คุณสร้างเซตได้โดยใส่สมาชิกไว้ใน วงเล็บปีกกา {} คั่นด้วยเครื่องหมายจุลภาค ถ้าใส่ค่าซ้ำเข้าไป Python จะข้ามค่าเหล่านั้นไปเงียบ ๆ

สร้างเซตด้วยวงเล็บปีกกา
# A basic set of fruits
fruits = {'apple', 'banana', 'cherry'}
print(fruits)
# Duplicates are automatically removed
colors = {'red', 'blue', 'red', 'green', 'blue'}
print(colors) # Only 3 unique colors
ผลลัพธ์
{'apple', 'banana', 'cherry'}
{'red', 'green', 'blue'}

สังเกตว่าลำดับในผลลัพธ์อาจดูต่างจากที่คุณพิมพ์ไว้ เพราะเซต ไม่มีลำดับ (unordered) Python จึงจัดเก็บสมาชิกภายในแบบใดก็ได้ อย่าพึ่งเซตในการรักษาลำดับที่เจาะจง

คุณยังสร้างเซตจากลิสต์ได้ด้วยคอนสตรัคเตอร์ set() นี่เป็นวิธียอดนิยมในการลบข้อมูลซ้ำออกจากลิสต์

สร้างเซตด้วยคอนสตรัคเตอร์ set()
# Convert a list with duplicates into a set
names_list = ['Alice', 'Bob', 'Alice', 'Charlie', 'Bob']
names_set = set(names_list)
print(names_set) # Only unique names
# Create a set from a string (each character becomes an item)
letters = set('hello')
print(letters) # {'h', 'e', 'l', 'o'} - only one 'l'
ผลลัพธ์
{'Bob', 'Alice', 'Charlie'}
{'o', 'l', 'e', 'h'}

การดำเนินการของเซต: ยูเนียน อินเตอร์เซกชัน และผลต่าง

พลังที่แท้จริงของเซตมาจาก การดำเนินการของเซต (set operations) ซึ่งใช้รวม เปรียบเทียบ และหาความต่างระหว่างเซต ลองนึกถึงแผนภาพเวนน์ในวิชาคณิตศาสตร์

ยูเนียน: รวมทุกอย่างเข้าด้วยกัน

ยูเนียน (union) ให้สมาชิกทั้งหมดจากทั้งสองเซตโดยไม่มีตัวซ้ำ ใช้ตัวดำเนินการ | หรือเมธอด .union() ก็ได้

ยูเนียนรวมสมาชิกที่ไม่ซ้ำทั้งหมด
math_students = {'Alice', 'Bob', 'Charlie'}
science_students = {'Bob', 'Diana', 'Charlie'}
# Union - everyone in either class
all_students = math_students | science_students
print(all_students)
# Same thing using the method
all_students = math_students.union(science_students)
print(all_students)
ผลลัพธ์
{'Charlie', 'Bob', 'Alice', 'Diana'}
{'Charlie', 'Bob', 'Alice', 'Diana'}

อินเตอร์เซกชัน: หาสิ่งที่มีร่วมกัน

อินเตอร์เซกชัน (intersection) ให้เฉพาะสมาชิกที่อยู่ใน ทั้งสอง เซต ใช้ตัวดำเนินการ & หรือ .intersection()

อินเตอร์เซกชันหาสมาชิกที่มีร่วมกัน
math_students = {'Alice', 'Bob', 'Charlie'}
science_students = {'Bob', 'Diana', 'Charlie'}
# Intersection - students in BOTH classes
both_classes = math_students & science_students
print(both_classes) # {'Bob', 'Charlie'}
ผลลัพธ์
{'Bob', 'Charlie'}

ผลต่าง: สิ่งที่มีเฉพาะในเซตเดียว

ผลต่าง (difference) ให้สมาชิกที่อยู่ในเซตแรกแต่ ไม่อยู่ ในเซตที่สอง ใช้ตัวดำเนินการ - หรือ .difference() ในกรณีนี้ลำดับของเซตมีผล

ผลต่างหาสมาชิกที่มีเฉพาะในเซตเดียว
math_students = {'Alice', 'Bob', 'Charlie'}
science_students = {'Bob', 'Diana', 'Charlie'}
# Who is ONLY in math?
math_only = math_students - science_students
print(math_only) # {'Alice'}
# Who is ONLY in science?
science_only = science_students - math_students
print(science_only) # {'Diana'}
ผลลัพธ์
{'Alice'}
{'Diana'}

ผลต่างสมมาตร: อยู่ในเซตใดเซตหนึ่ง แต่ไม่อยู่ในทั้งสองเซต

ผลต่างสมมาตร (symmetric difference) ให้สมาชิกที่อยู่ในเซต ใดเซตหนึ่ง แต่ ไม่อยู่ในทั้งสองเซต มองได้ว่าเป็นสิ่งตรงข้ามกับอินเตอร์เซกชัน ใช้ตัวดำเนินการ ^ หรือ .symmetric_difference()

ผลต่างสมมาตรตัดสมาชิกที่มีร่วมกันออก
math_students = {'Alice', 'Bob', 'Charlie'}
science_students = {'Bob', 'Diana', 'Charlie'}
# Students in only ONE class (not both)
exclusive = math_students ^ science_students
print(exclusive) # {'Alice', 'Diana'}
ผลลัพธ์
{'Alice', 'Diana'}

วิธีเพิ่มและลบสมาชิกในเซต

เซต เปลี่ยนแปลงได้ (mutable) หมายความว่าคุณเพิ่มและลบสมาชิกได้หลังสร้างเซตแล้ว นี่คือเมธอดหลัก ๆ ที่คุณจะได้ใช้

เพิ่มและลบสมาชิกในเซต
fruits = {'apple', 'banana'}
# Add a single item
fruits.add('cherry')
print(fruits)
# Add multiple items at once
fruits.update(['date', 'elderberry'])
print(fruits)
# Remove an item (raises error if not found)
fruits.remove('banana')
print(fruits)
# Discard an item (no error if not found)
fruits.discard('mango') # No crash!
print(fruits)
ผลลัพธ์
{'apple', 'banana', 'cherry'}
{'date', 'elderberry', 'apple', 'banana', 'cherry'}
{'date', 'elderberry', 'apple', 'cherry'}
{'date', 'elderberry', 'apple', 'cherry'}

คุณยังล้างสมาชิกทั้งหมด หรือดึงสมาชิกตัวใดตัวหนึ่งออกจากเซตได้ด้วย (โดยเลือกเองไม่ได้ว่าจะได้ตัวไหน)

เมธอด pop และ clear
numbers = {10, 20, 30, 40, 50}
# Pop removes and returns an arbitrary item
removed = numbers.pop()
print(f'Removed: {removed}')
print(f'Remaining: {numbers}')
# Clear removes everything
numbers.clear()
print(numbers) # set()
ผลลัพธ์
Removed: 50
Remaining: {20, 40, 10, 30}
set()

ทำไมเซตจึงตรวจสอบการเป็นสมาชิกได้เร็วมาก

เหตุผลดี ๆ ข้อหนึ่งที่ควรใช้เซตคือ การตรวจว่ามีบางสิ่งอยู่หรือไม่ คีย์เวิร์ด in ใช้ได้ทั้งกับลิสต์และเซต แต่เซตเร็วกว่า มาก

ตรวจสอบการเป็นสมาชิกอย่างรวดเร็วด้วย in
allowed_users = {'alice', 'bob', 'charlie', 'diana'}
user = 'bob'
if user in allowed_users:
print(f'{user} is allowed!')
else:
print(f'{user} is not allowed.')
# Checking who is NOT in the set
user2 = 'eve'
if user2 not in allowed_users:
print(f'{user2} is not on the list.')
ผลลัพธ์
bob is allowed!
eve is not on the list.

Frozenset คืออะไร

frozenset คือเซตแบบเปลี่ยนแปลงไม่ได้ (immutable) เมื่อสร้างแล้วจะเพิ่มหรือลบสมาชิกไม่ได้ ทำให้ frozenset แฮชได้ (hashable) หมายความว่าใช้เป็นคีย์ของดิกชันนารีหรือเก็บไว้ในเซตอื่นได้

Frozenset คือเซตที่เปลี่ยนแปลงไม่ได้
# Create a frozenset
vowels = frozenset(['a', 'e', 'i', 'o', 'u'])
print(vowels)
# You can still do set operations
consonants = frozenset(['b', 'c', 'd', 'f', 'g'])
all_letters = vowels | consonants
print(all_letters)
# But you CANNOT modify it
# vowels.add('y') # AttributeError!
ผลลัพธ์
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()

emails = ['alice@mail.com', 'bob@mail.com', 'alice@mail.com', 'charlie@mail.com', 'bob@mail.com']
# Create a set of unique emails and print them sorted
ทายผลลัพธ์ของเซต
ทายผลลัพธ์

โค้ดนี้แสดงผลอะไร คิดให้ดีว่าเซตจัดการกับข้อมูลซ้ำอย่างไร และฟังก์ชัน len() คืนค่าอะไร

data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = set(data)
print(len(unique))

เขียนคำสั่ง print() ที่ให้ผลลัพธ์ตรงทุกตัวอักษร

# What does this code print?
data = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = set(data)
print(len(unique))
หานักเรียนที่เรียนทั้งสองวิชา
เขียนโค้ด

คุณมีเซตสองเซต คือ math และ english หาและแสดงรายชื่อนักเรียนที่ลงทะเบียนเรียน ทั้งสอง วิชา แสดงผลเป็นลิสต์ที่เรียงลำดับแล้ว

math = {'Alice', 'Bob', 'Charlie', 'Diana'}
english = {'Bob', 'Diana', 'Eve', 'Frank'}
# Find students in both classes and print sorted
แก้บั๊กเซตว่าง
แก้บั๊ก

โค้ดนี้พยายามสร้างเซตว่าง เพิ่มสมาชิกเข้าไป แล้วแสดงผลลัพธ์ แต่มีบั๊ก เพราะคนเขียนใช้ {} สร้างเซตว่าง แก้บั๊กให้โค้ดทำงานได้ถูกต้อง

# Bug: this creates a dictionary, not a set!
my_set = {}
my_set.add('python')
my_set.add('java')
my_set.add('python') # duplicate
print(sorted(my_set))
หาวัตถุดิบที่ยังขาด
เขียนโค้ด

คุณมีเซต recipe ที่มีวัตถุดิบทั้งหมดที่สูตรอาหารต้องใช้ และเซต pantry ที่มีของที่คุณมีอยู่แล้ว หาวัตถุดิบที่ยังต้องซื้อเพิ่ม แล้วแสดงผลเป็นลิสต์ที่เรียงลำดับแล้ว

recipe = {'flour', 'sugar', 'eggs', 'butter', 'vanilla'}
pantry = {'flour', 'eggs', 'salt', 'pepper'}
# Find and print what you need to buy (sorted)
ลบข้อมูลซ้ำโดยรักษาลำดับเดิม
เขียนโค้ด

เขียนฟังก์ชันชื่อ dedupe(items) ที่ลบข้อมูลซ้ำออกจากลิสต์โดยรักษาลำดับเดิมไว้ ใช้เซตจดว่าเจอสมาชิกตัวไหนไปแล้วบ้าง แล้วคืนค่าลิสต์ที่ไม่มีข้อมูลซ้ำ

ทดสอบด้วยการเรียก print(dedupe([3, 1, 4, 1, 5, 9, 2, 6, 5, 3]))

def dedupe(items):
# Use a set to track seen items
# Build a new list with only first occurrences
pass
print(dedupe([3, 1, 4, 1, 5, 9, 2, 6, 5, 3]))

บทเรียนที่เกี่ยวข้อง

บทเรียนนี้มีประโยชน์หรือไม่