Bài 8: Sets - Tập Hợp

Mục Tiêu Bài Học

Sau khi hoàn thành bài này, bạn sẽ:

  • ✅ Hiểu set là gì và tính chất unique
  • ✅ Tạo và thao tác với sets
  • ✅ Sử dụng set operations (union, intersection, difference)
  • ✅ Phân biệt set vs list vs tuple vs dict
  • ✅ Áp dụng sets trong các bài toán thực tế

Set Là Gì?

Set là collection không có thứ tự, không cho phép phần tử trùng lặp, và các phần tử phải immutable (hashable).

# Set với dấu ngoặc nhọn {}fruits = {"apple", "banana", "orange"}numbers = {1, 2, 3, 4, 5} print(type(fruits))  # <class 'set'>

Tính chất quan trọng:

# 1. Không có duplicatenumbers = {1, 2, 2, 3, 3, 3}print(numbers)  # {1, 2, 3} (tự động loại bỏ trùng) # 2. Không có thứ tự (unordered)my_set = {3, 1, 2}print(my_set)  # {1, 2, 3} hoặc bất kỳ thứ tự nào # 3. Không thể index# print(my_set[0])  # TypeError! # 4. Phần tử phải immutablevalid_set = {1, "hello", (1, 2), 3.14}  # ✅ OK# invalid_set = {[1, 2], {3, 4}}  # ❌ TypeError!

Khi nào dùng Set:

  • ✅ Loại bỏ duplicates
  • ✅ Membership testing (nhanh)
  • ✅ Set operations (union, intersection, difference)
  • ✅ Mathematical operations

Tạo Set

Cách 1: Dùng Dấu Ngoặc Nhọn {}

# Set với phần tửfruits = {"apple", "banana", "orange"}numbers = {1, 2, 3, 4, 5}mixed = {1, "hello", 3.14, True} # ⚠️ Empty set KHÔNG dùng {}empty = {}  # Này là dict, không phải set!print(type(empty))  # <class 'dict'> # ✅ Empty set dùng set()empty_set = set()print(type(empty_set))  # <class 'set'>

Cách 2: set() Constructor

# Từ list (loại bỏ duplicates)my_list = [1, 2, 2, 3, 3, 3]my_set = set(my_list)print(my_set)  # {1, 2, 3} # Từ string (unique characters)chars = set("hello")print(chars)  # {'h', 'e', 'l', 'o'} # Từ tuplemy_tuple = (1, 2, 2, 3)my_set = set(my_tuple)print(my_set)  # {1, 2, 3} # Từ rangenumbers = set(range(5))print(numbers)  # {0, 1, 2, 3, 4}

Cách 3: Set Comprehension

# Set comprehensionsquares = {x**2 for x in range(5)}print(squares)  # {0, 1, 4, 9, 16} # Với điều kiệnevens = {x for x in range(10) if x % 2 == 0}print(evens)  # {0, 2, 4, 6, 8} # Từ stringvowels = {c for c in "hello world" if c in "aeiou"}print(vowels)  # {'e', 'o'}

Thêm và Xóa Phần Tử

Thêm Phần Tử

fruits = {"apple", "banana"} # add() - thêm một phần tửfruits.add("orange")print(fruits)  # {'apple', 'banana', 'orange'} # Thêm phần tử đã tồn tại (không làm gì)fruits.add("apple")print(fruits)  # {'apple', 'banana', 'orange'} (không đổi) # update() - thêm nhiều phần tử (từ iterable)fruits.update(["mango", "grape"])print(fruits)  # {'apple', 'banana', 'orange', 'mango', 'grape'} # update với nhiều iterablesfruits.update(["kiwi"], {"pear"}, ("melon",))print(fruits)

Xóa Phần Tử

fruits = {"apple", "banana", "orange", "mango"} # remove() - xóa phần tử (lỗi nếu không tồn tại)fruits.remove("banana")print(fruits)  # {'apple', 'orange', 'mango'} # fruits.remove("grape")  # KeyError! # discard() - xóa phần tử (không lỗi nếu không tồn tại)fruits.discard("orange")print(fruits)  # {'apple', 'mango'} fruits.discard("grape")  # Không lỗiprint(fruits)  # {'apple', 'mango'} # pop() - xóa phần tử bất kỳ (random)item = fruits.pop()print(f"Removed: {item}")print(fruits) # clear() - xóa tất cảfruits.clear()print(fruits)  # set()

Set Operations - Phép Toán Tập Hợp

Union (Hợp) - |

Union là tất cả phần tử từ cả 2 sets.

set1 = {1, 2, 3}set2 = {3, 4, 5} # Union với | operatorunion1 = set1 | set2print(union1)  # {1, 2, 3, 4, 5} # Union với union() methodunion2 = set1.union(set2)print(union2)  # {1, 2, 3, 4, 5} # Union nhiều setsset3 = {5, 6, 7}union3 = set1 | set2 | set3print(union3)  # {1, 2, 3, 4, 5, 6, 7} # Ví dụ thực tếpython_students = {"Alice", "Bob", "Charlie"}java_students = {"Bob", "Diana", "Eve"}all_students = python_students | java_studentsprint(f"Total students: {all_students}")

Intersection (Giao) - &

Intersection là phần tử có ở cả 2 sets.

set1 = {1, 2, 3, 4}set2 = {3, 4, 5, 6} # Intersection với & operatorinter1 = set1 & set2print(inter1)  # {3, 4} # Intersection với intersection() methodinter2 = set1.intersection(set2)print(inter2)  # {3, 4} # Ví dụ thực tếpython_students = {"Alice", "Bob", "Charlie"}java_students = {"Bob", "Diana", "Eve"}both_courses = python_students & java_studentsprint(f"Students in both: {both_courses}")  # {'Bob'}

Difference (Hiệu) - -

Difference là phần tử có trong set1 nhưng không có trong set2.

set1 = {1, 2, 3, 4}set2 = {3, 4, 5, 6} # Difference với - operatordiff1 = set1 - set2print(diff1)  # {1, 2} # Difference với difference() methoddiff2 = set1.difference(set2)print(diff2)  # {1, 2} # ⚠️ Thứ tự quan trọng!print(set1 - set2)  # {1, 2}print(set2 - set1)  # {5, 6} # Ví dụ thực tếpython_students = {"Alice", "Bob", "Charlie"}java_students = {"Bob", "Diana", "Eve"}python_only = python_students - java_studentsprint(f"Python only: {python_only}")  # {'Alice', 'Charlie'}

Symmetric Difference (Hiệu Đối Xứng) - ^

Symmetric Difference là phần tử có trong set1 hoặc set2 nhưng không có trong cả hai.

set1 = {1, 2, 3, 4}set2 = {3, 4, 5, 6} # Symmetric difference với ^ operatorsym_diff1 = set1 ^ set2print(sym_diff1)  # {1, 2, 5, 6} # Symmetric difference với symmetric_difference() methodsym_diff2 = set1.symmetric_difference(set2)print(sym_diff2)  # {1, 2, 5, 6} # Tương đương: (A - B) | (B - A)result = (set1 - set2) | (set2 - set1)print(result)  # {1, 2, 5, 6} # Ví dụ thực tếpython_students = {"Alice", "Bob", "Charlie"}java_students = {"Bob", "Diana", "Eve"}exclusive = python_students ^ java_studentsprint(f"Exclusive students: {exclusive}")# {'Alice', 'Charlie', 'Diana', 'Eve'}

Tổng Hợp Set Operations

A = {1, 2, 3, 4, 5}B = {4, 5, 6, 7, 8} print(f"A: {A}")print(f"B: {B}")print(f"A | B (Union):      {A | B}")      # {1, 2, 3, 4, 5, 6, 7, 8}print(f"A & B (Intersection): {A & B}")    # {4, 5}print(f"A - B (Difference):   {A - B}")    # {1, 2, 3}print(f"B - A (Difference):   {B - A}")    # {6, 7, 8}print(f"A ^ B (Sym Diff):     {A ^ B}")    # {1, 2, 3, 6, 7, 8}

Set Comparison

Subset và Superset

set1 = {1, 2, 3}set2 = {1, 2, 3, 4, 5} # Subset - tất cả phần tử của A có trong Bprint(set1.issubset(set2))    # Trueprint(set1 <= set2)           # True # Proper subset - subset nhưng không bằngprint(set1 < set2)            # Trueprint(set1 < set1)            # False # Superset - A chứa tất cả phần tử của Bprint(set2.issuperset(set1))  # Trueprint(set2 >= set1)           # True # Proper supersetprint(set2 > set1)            # Trueprint(set2 > set2)            # False # Disjoint - không có phần tử chungset3 = {6, 7, 8}print(set1.isdisjoint(set3))  # Trueprint(set1.isdisjoint(set2))  # False

Equality

set1 = {1, 2, 3}set2 = {3, 2, 1}  # Thứ tự không quan trọngset3 = {1, 2, 3, 3}  # Duplicate bị loại bỏ print(set1 == set2)  # Trueprint(set1 == set3)  # Trueprint(set1 != set3)  # False

Set Methods Khác

my_set = {1, 2, 3, 4, 5} # len() - số phần tửprint(len(my_set))  # 5 # in operator - check membership (rất nhanh - O(1))print(3 in my_set)       # Trueprint(10 in my_set)      # Falseprint(10 not in my_set)  # True # min(), max() - nhỏ nhất, lớn nhấtprint(min(my_set))  # 1print(max(my_set))  # 5 # sum() - tổngprint(sum(my_set))  # 15 # sorted() - trả về list đã sắp xếpsorted_list = sorted(my_set)print(sorted_list)  # [1, 2, 3, 4, 5] # any(), all()print(any(my_set))  # Trueprint(all(my_set))  # True bools = {True, False}print(any(bools))   # Trueprint(all(bools))   # False

Frozenset - Immutable Set

Frozenset là set không thể thay đổi (immutable).

# Tạo frozensetfs = frozenset([1, 2, 3, 4])print(fs)  # frozenset({1, 2, 3, 4}) # Không thể thay đổi# fs.add(5)  # AttributeError!# fs.remove(1)  # AttributeError! # Có thể làm dictionary key hoặc set elementmy_dict = {    frozenset([1, 2]): "A",    frozenset([3, 4]): "B"}print(my_dict[frozenset([1, 2])])  # A # Set of frozensetsset_of_sets = {frozenset([1, 2]), frozenset([3, 4])}print(set_of_sets) # Operations vẫn hoạt độngfs1 = frozenset([1, 2, 3])fs2 = frozenset([3, 4, 5])print(fs1 | fs2)  # frozenset({1, 2, 3, 4, 5})

Ví Dụ Thực Tế

1. Remove Duplicates

# List có duplicatesnumbers = [1, 2, 2, 3, 4, 4, 5, 5, 5] # Convert to set để loại bỏ duplicatesunique_numbers = list(set(numbers))print(unique_numbers)  # [1, 2, 3, 4, 5] (không đảm bảo thứ tự) # Giữ thứ tự (dùng dict.fromkeys)unique_ordered = list(dict.fromkeys(numbers))print(unique_ordered)  # [1, 2, 3, 4, 5] # Ví dụ với stringsemails = [    "[email protected]",    "[email protected]",    "[email protected]",  # Duplicate    "[email protected]",    "[email protected]"  # Duplicate] unique_emails = list(set(emails))print(f"Unique emails: {len(unique_emails)}")for email in sorted(unique_emails):    print(f"  {email}")

2. Tag System

# Posts với tagsposts = [    {"id": 1, "title": "Python Basics", "tags": {"python", "tutorial", "beginner"}},    {"id": 2, "title": "Django Web", "tags": {"python", "django", "web"}},    {"id": 3, "title": "React JS", "tags": {"javascript", "react", "web"}},    {"id": 4, "title": "Python Advanced", "tags": {"python", "advanced"}}] # Tất cả tagsall_tags = set()for post in posts:    all_tags |= post["tags"]  # Union print(f"All tags: {all_tags}") # Posts có tag 'python'python_posts = [p for p in posts if "python" in p["tags"]]print(f"\nPosts with 'python': {len(python_posts)}") # Posts có cả 'python' và 'web'required_tags = {"python", "web"}matching_posts = [p for p in posts if required_tags.issubset(p["tags"])]print(f"Posts with 'python' AND 'web': {len(matching_posts)}") # Common tags giữa 2 postscommon = posts[0]["tags"] & posts[1]["tags"]print(f"\nCommon tags between post 1 and 2: {common}")

3. Permission System

# User permissionsadmin_permissions = {"read", "write", "delete", "manage_users"}editor_permissions = {"read", "write"}viewer_permissions = {"read"} # User rolesusers = {    "Alice": admin_permissions,    "Bob": editor_permissions,    "Charlie": viewer_permissions} # Check permissiondef has_permission(user, permission):    return permission in users.get(user, set()) print(has_permission("Alice", "delete"))    # Trueprint(has_permission("Bob", "delete"))      # False # Users có thể writecan_write = [user for user, perms in users.items() if "write" in perms]print(f"Users with write: {can_write}") # Thêm permissionusers["Bob"].add("delete")print(f"Bob's permissions: {users['Bob']}") # Xóa permissionusers["Bob"].discard("delete")print(f"Bob's permissions: {users['Bob']}")

4. Data Validation

# Valid optionsVALID_ROLES = {"admin", "editor", "viewer", "guest"}VALID_STATUS = {"active", "inactive", "pending", "suspended"} # Validate user datadef validate_user(user_data):    errors = []        # Check required fields    required = {"username", "email", "role"}    missing = required - set(user_data.keys())    if missing:        errors.append(f"Missing fields: {missing}")        # Validate role    if "role" in user_data and user_data["role"] not in VALID_ROLES:        errors.append(f"Invalid role: {user_data['role']}")        # Validate status    if "status" in user_data and user_data["status"] not in VALID_STATUS:        errors.append(f"Invalid status: {user_data['status']}")        return errors # Testuser1 = {"username": "alice", "email": "[email protected]", "role": "admin"}user2 = {"username": "bob", "role": "superuser"}  # Missing email, invalid role print("User 1 errors:", validate_user(user1))print("User 2 errors:", validate_user(user2))

5. Find Common Friends

# Social network - friendsfriends = {    "Alice": {"Bob", "Charlie", "Diana"},    "Bob": {"Alice", "Charlie", "Eve"},    "Charlie": {"Alice", "Bob", "Frank"},    "Diana": {"Alice"},    "Eve": {"Bob"},    "Frank": {"Charlie"}} # Common friendsdef common_friends(person1, person2):    return friends.get(person1, set()) & friends.get(person2, set()) # Mutual friendsmutual = common_friends("Alice", "Bob")print(f"Alice & Bob mutual friends: {mutual}")  # {'Charlie'} # Friend suggestions (friends of friends)def suggest_friends(person):    person_friends = friends.get(person, set())    suggestions = set()        for friend in person_friends:        # Friends của friend        friends_of_friend = friends.get(friend, set())        suggestions |= friends_of_friend        # Loại bỏ person và friends hiện tại    suggestions -= {person}    suggestions -= person_friends        return suggestions suggestions = suggest_friends("Alice")print(f"Friend suggestions for Alice: {suggestions}")

Bài Tập Thực Hành

Bài 1: Set Operations

Cho 2 sets A và B, tính:

  • Union
  • Intersection
  • Difference (A-B và B-A)
  • Symmetric difference
  • Check A là subset của B không

Bài 2: Find Duplicates

Viết function tìm duplicates trong list:

  • Input: [1, 2, 3, 2, 4, 3, 5]
  • Output: {2, 3}

Bài 3: Common Elements

Tìm phần tử xuất hiện trong tất cả lists:

  • Lists: [[1,2,3], [2,3,4], [3,4,5]]
  • Result: {3}

Bài 4: Unique Words

Đếm unique words trong text:

  • Loại bỏ duplicates
  • Case-insensitive
  • Ignore punctuation

Bài 5: Skills Matching

Cho job requirements và candidate skills:

  • Tìm candidates đủ điều kiện
  • Tìm skills còn thiếu
  • Rank candidates by matching score

Tóm Tắt

✅ Set: unordered, unique elements, mutable
✅ Tạo: {}, set(), set comprehension
✅ Operations: | (union), & (intersection), - (difference), ^ (symmetric diff)
✅ Comparison: subset <=, superset >=, disjoint
✅ Methods: add(), remove(), discard(), pop(), clear()
✅ Frozenset: immutable set, có thể làm dict key
✅ Use cases: remove duplicates, membership testing, set operations

Bài Tiếp Theo

Bài 9: Control Flow - If/Else - Conditional statements, if-elif-else, và logical operators.


Remember:

  • Sets không có thứ tự và không có duplicates
  • Membership testing với set rất nhanh (O(1))
  • Dùng sets cho mathematical operations
  • Frozenset cho immutable requirements
  • Set operations: intuitive và powerful!
  • Practice với real data để master sets!