Tìm hiểu Set trong Python

Python Tutorial | by Hoc Python

Trong lập trình, việc lựa chọn cấu trúc dữ liệu phù hợp là một yếu tố then chốt để viết code hiệu quả. Bạn đã quen thuộc với List và Tuple, nhưng Python còn cung cấp một cấu trúc mạnh mẽ khác: Set (tập hợp).Set được thiết kế đặc biệt để xử lý các tập hợp dữ liệu mà bạn muốn đảm bảo không có bất kỳ phần tử nào bị trùng lặp. Bài viết này sẽ đưa bạn đi tìm hiểu Set từ những khái niệm cơ bản nhất, cách tạo Set, các đặc điểm độc đáo của nó, cho đến những thao tác và ứng dụng mạnh mẽ nhất. Hãy cùng tìm hiểu cách Set có thể giúp bạn giải quyết các bài toán liên quan đến dữ liệu duy nhất một cách cực kỳ hiệu quả nhé!

Set là gì?

Set trong Python là một cấu trúc dữ liệu dùng để lưu trữ một tập hợp các phần tử. Đặc điểm cơ bản và quan trọng nhất của Set là:

  • Chứa các phần tử duy nhất (Unique): Một Set không thể có hai phần tử giống hệt nhau. Khi bạn cố gắng thêm một phần tử đã tồn tại vào Set, nó sẽ không thay đổi.

  • Không có thứ tự (Unordered): Các phần tử trong Set không được sắp xếp theo một thứ tự cụ thể nào cả. Điều này có nghĩa là bạn không thể truy cập các phần tử bằng chỉ số (index) như my_set[0].

Bạn có thể tạo một Set bằng cách đặt các phần tử bên trong cặp dấu ngoặc nhọn {} hoặc sử dụng hàm set().

Ví dụ:

# Tạo một Set với các phần tử trùng lặp
my_set = {1, 2, 3, 2, 4, 1}
print(f"Set sau khi được tạo: {my_set}")
# Output: Set sau khi được tạo: {1, 2, 3, 4}
# Lưu ý: Các phần tử trùng lặp (1 và 2) đã tự động bị loại bỏ.

# Set không có thứ tự, nên thứ tự in ra có thể khác nhau

Điểm khác biệt chính (Set vs List & Tuple)

Để hiểu rõ hơn về Set, hãy so sánh nó với List và Tuple:

Đặc điểm List Tuple Set
Thứ tự Có thứ tự (Ordered) Có thứ tự (Ordered) Không có thứ tự (Unordered)
Trùng lặp Cho phép trùng lặp Cho phép trùng lặp Không cho phép trùng lặp
Thay đổi Có thể thay đổi (Mutable) Bất biến (Immutable) Có thể thay đổi (Mutable)
Cú pháp [item1, item2, ...] (item1, item2, ...) {item1, item2, ...} hoặc set()
Truy cập Bằng chỉ số (my_list[0]) Bằng chỉ số (my_tuple[0]) Không thể bằng chỉ số

Tóm lại:

  • List: Dùng để lưu trữ bộ sưu tập có thứ tự, có thể thay đổi và cho phép trùng lặp.

  • Tuple: Dùng để lưu trữ bộ sưu tập có thứ tự, bất biến và cho phép trùng lặp.

  • Set: Dùng để lưu trữ bộ sưu tập duy nhất, không có thứ tự và có thể thay đổi.

Khi nào dùng Set?

Set là một công cụ mạnh mẽ và tối ưu cho các trường hợp sau:

Loại bỏ các phần tử trùng lặp: Đây là ứng dụng phổ biến và trực quan nhất của Set. Nếu bạn có một danh sách chứa nhiều phần tử bị lặp và chỉ muốn giữ lại các giá trị duy nhất, việc chuyển List đó sang Set là cách nhanh nhất.

  • Ví dụ:

my_list_with_duplicates = [1, 5, 2, 8, 5, 1, 9, 2, 8]
unique_elements = set(my_list_with_duplicates)
print(f"List gốc: {my_list_with_duplicates}")
print(f"Các phần tử duy nhất: {unique_elements}")
# Output:
# List gốc: [1, 5, 2, 8, 5, 1, 9, 2, 8]
# Các phần tử duy nhất: {1, 2, 5, 8, 9}

Kiểm tra sự tồn tại của phần tử một cách nhanh chóng: Do cách tổ chức dữ liệu bên trong, việc kiểm tra xem một phần tử có tồn tại trong Set hay không (if element in my_set:) nhanh hơn đáng kể so với List hoặc Tuple, đặc biệt với các tập hợp dữ liệu lớn.

Ví dụ:

inventory = {"apple", "banana", "orange", "grape"}

if "apple" in inventory:
    print("Táo có trong kho.") # Output: Táo có trong kho.

if "mango" in inventory:
    print("Xoài có trong kho.")
else:
    print("Xoài không có trong kho.") # Output: Xoài không có trong kho.

Thực hiện các phép toán tập hợp: Set được xây dựng dựa trên lý thuyết tập hợp trong toán học. Điều này cho phép bạn thực hiện các phép toán như hợp (union), giao (intersection), hiệu (difference) một cách dễ dàng và hiệu quả.

Ví dụ:

group_a = {"An", "Bình", "Cúc"}
group_b = {"Bình", "Dũng", "An"}

# Tìm những người có cả ở nhóm A và B (phép giao)
in_both_groups = group_a.intersection(group_b)
print(f"Những người có trong cả hai nhóm: {in_both_groups}") # Output: Những người có trong cả hai nhóm: {'An', 'Bình'}

Set là một cấu trúc dữ liệu mạnh mẽ, giúp giải quyết các bài toán liên quan đến dữ liệu duy nhất và các phép toán tập hợp một cách tự nhiên và hiệu quả trong Python.

Khởi tạo Set trong Python

Có nhiều cách để tạo một Set trong Python, tùy thuộc vào việc bạn muốn tạo một Set rỗng hay một Set đã có sẵn các phần tử từ ban đầu.

Tạo Set rỗng

Cú pháp: my_set = set()

Ví dụ:

empty_set = set()
print(f"Set rỗng được tạo: {empty_set}")
print(f"Kiểu dữ liệu: {type(empty_set)}")
# Output:
# Set rỗng được tạo: set()
# Kiểu dữ liệu: <class 'set'>

Tại sao không dùng {}? Đây là một lưu ý rất quan trọng và thường gây nhầm lẫn cho người mới học. Khi bạn sử dụng cú pháp {}, Python sẽ mặc định hiểu đó là một Dictionary (từ điển) rỗng, chứ không phải một Set rỗng. Để tạo một Set rỗng, bạn phải sử dụng hàm set().

# Dùng {} để tạo một Dictionary rỗng
empty_dict = {}
print(f"Đối tượng được tạo bằng {{}}: {empty_dict}")
print(f"Kiểu dữ liệu: {type(empty_dict)}")
# Output:
# Đối tượng được tạo bằng {}: {}
# Kiểu dữ liệu: <class 'dict'>

Tạo Set với các phần tử

Cú pháp: my_set = {item1, item2, ...}

Giải thích: Bạn chỉ cần đặt các phần tử bên trong dấu ngoặc nhọn {} và phân tách chúng bằng dấu phẩy ,. Python sẽ tự động tạo một Set và loại bỏ mọi phần tử trùng lặp.

Ví dụ:

Set số:

numbers = {1, 5, 3, 2, 5, 1}
print(f"Set số: {numbers}")
# Output: Set số: {1, 2, 3, 5}
# Các số 1 và 5 trùng lặp đã bị loại bỏ.

Set chuỗi:

fruits = {"apple", "banana", "apple", "cherry"}
print(f"Set chuỗi: {fruits}")
# Output: Set chuỗi: {'apple', 'banana', 'cherry'}
# 'apple' trùng lặp đã bị loại bỏ.

Set hỗn hợp: Một Set có thể chứa các kiểu dữ liệu khác nhau, miễn là các phần tử đó là bất biến (immutable). Vì vậy, bạn có thể có số, chuỗi, và Tuple trong Set, nhưng không thể có List hay Dictionary.

mixed_set = {1, "hello", (1, 2, 3)}
print(f"Set hỗn hợp: {mixed_set}")
# Output: Set hỗn hợp: {(1, 2, 3), 1, 'hello'}

# Ví dụ lỗi khi cố gắng thêm List hoặc Dictionary
try:
    invalid_set = {1, ["list"]}
except TypeError as e:
    print(f"Lỗi: {e}")
    # Output: Lỗi: unhashable type: 'list'

Tạo Set từ List hoặc Tuple

Cú pháp: my_set = set(iterable)

Giải thích: Bạn có thể truyền một đối tượng có thể lặp (iterable) như List, Tuple, hoặc thậm chí là một chuỗi vào hàm set(). Python sẽ duyệt qua các phần tử của đối tượng đó và tạo một Set mới, tự động loại bỏ các phần tử trùng lặp và không giữ lại thứ tự ban đầu.

Ví dụ:

Từ List:

my_list = [10, 20, 10, 30, 20, 40]
my_set_from_list = set(my_list)
print(f"List gốc: {my_list}")
print(f"Set từ List: {my_set_from_list}")
# Output:
# List gốc: [10, 20, 10, 30, 20, 40]
# Set từ List: {40, 10, 20, 30}

Từ Tuple:

my_tuple = ("a", "b", "c", "a")
my_set_from_tuple = set(my_tuple)
print(f"Tuple gốc: {my_tuple}")
print(f"Set từ Tuple: {my_set_from_tuple}")
# Output:
# Tuple gốc: ('a', 'b', 'c', 'a')
# Set từ Tuple: {'a', 'b', 'c'}

Từ chuỗi:

my_string = "hello"
my_set_from_string = set(my_string)
print(f"Chuỗi gốc: {my_string}")
print(f"Set từ chuỗi: {my_set_from_string}")
# Output:
# Chuỗi gốc: hello
# Set từ chuỗi: {'e', 'o', 'l', 'h'}
# Các chữ cái trùng lặp 'l' đã bị loại bỏ.

Việc tạo Set rất đơn giản. Hãy nhớ rằng {} chỉ dùng để tạo Set có phần tử, còn set() dùng để tạo Set rỗng hoặc chuyển đổi từ các iterable khác.

Đặc điểm của Set trong Python

Để sử dụng Set hiệu quả, bạn cần nắm vững ba đặc điểm cốt lõi của nó. Những đặc điểm này phân biệt Set với List và Tuple, đồng thời quyết định cách bạn tương tác với nó.

Không có thứ tự (Unordered)

  • Giải thích: Khác với List và Tuple, các phần tử trong Set không được lưu trữ theo một thứ tự cố định. Khi bạn tạo một Set, Python sắp xếp các phần tử theo một cách riêng để tối ưu hóa việc tìm kiếm, nhưng thứ tự này không được đảm bảo và có thể thay đổi giữa các lần chạy.

  • Hệ quả: Vì không có thứ tự, bạn không thể truy cập các phần tử bằng chỉ số (index) hoặc sử dụng kỹ thuật cắt lát (slicing). Nếu bạn cố gắng làm điều này, Python sẽ báo lỗi.

Ví dụ minh họa:

my_set = {"apple", "banana", "cherry"}

# Truy cập bằng chỉ số sẽ gây lỗi
try:
    print(my_set[0])
except TypeError as e:
    print(f"Lỗi: {e}")
    # Output: Lỗi: 'set' object is not subscriptable

# Cắt lát cũng sẽ gây lỗi
try:
    print(my_set[:2])
except TypeError as e:
    print(f"Lỗi: {e}")
    # Output: Lỗi: 'set' object is not subscriptable

Không chứa phần tử trùng lặp (No Duplicates)

  • Giải thích: Đây là đặc điểm nổi bật nhất của Set. Mỗi phần tử trong Set là duy nhất. Nếu bạn cố gắng thêm một phần tử đã tồn tại vào Set, thao tác đó sẽ bị bỏ qua và Set sẽ không thay đổi. Tính chất này khiến Set trở thành công cụ hoàn hảo để loại bỏ các phần tử trùng lặp trong một danh sách dữ liệu.

Ví dụ minh họa:

# Tạo một Set với các phần tử trùng lặp
numbers = {1, 2, 3, 2, 1, 4}
print(f"Set gốc: {numbers}") # Output: Set gốc: {1, 2, 3, 4}
# Các số 1 và 2 trùng lặp đã tự động bị loại bỏ.

# Thêm một phần tử đã tồn tại
numbers.add(3)
print(f"Set sau khi thêm số 3: {numbers}") # Output: Set sau khi thêm số 3: {1, 2, 3, 4}
# Số 3 đã có, nên Set không thay đổi.

# Thêm một phần tử mới
numbers.add(5)
print(f"Set sau khi thêm số 5: {numbers}") # Output: Set sau khi thêm số 5: {1, 2, 3, 4, 5}
# Số 5 là mới, nên đã được thêm vào.

Có thể thay đổi (Mutable)

  • Giải thích: Mặc dù các phần tử bên trong Set không có thứ tự và không thể truy cập bằng chỉ số, bản thân đối tượng Set lại có thể thay đổi (mutable). Điều này có nghĩa là bạn có thể thêm hoặc xóa các phần tử khỏi một Set sau khi nó đã được tạo.

  • Lưu ý quan trọng: Mặc dù Set có thể thay đổi, nhưng các phần tử bên trong Set phải là các đối tượng bất biến (immutable). Đây là lý do bạn có thể thêm số, chuỗi, hoặc Tuple vào Set, nhưng không thể thêm List hay Dictionary. Python cần các phần tử bên trong Set phải "bất biến" để tính toán mã băm (hash) và quản lý việc tìm kiếm hiệu quả.

Ví dụ minh họa

my_set = {"apple", "banana"}
print(f"Set ban đầu: {my_set}") # Output: Set ban đầu: {'apple', 'banana'}

# Thêm một phần tử mới (hợp lệ)
my_set.add("cherry")
print(f"Set sau khi thêm 'cherry': {my_set}") # Output: Set sau khi thêm 'cherry': {'apple', 'banana', 'cherry'}

# Thêm một Tuple (hợp lệ vì Tuple là immutable)
my_set.add(("grape", "orange"))
print(f"Set sau khi thêm Tuple: {my_set}") # Output: Set sau khi thêm Tuple: {'apple', 'banana', 'cherry', ('grape', 'orange')}

# Cố gắng thêm một List (sẽ gây lỗi vì List là mutable)
try:
    my_set.add(["kiwi", "melon"])
except TypeError as e:
    print(f"Lỗi: {e}")
    # Output: Lỗi: unhashable type: 'list'
Việc nắm vững ba đặc điểm này sẽ giúp bạn hiểu rõ vai trò và cách sử dụng Set trong các tình huống lập trình khác nhau, đặc biệt là khi so sánh với List và Tuple.

Các Thao tác Phổ biến với Set trong Python

Bài viết liên quan