Chuyển đến nội dung chính

Hướng dẫn Python Set và Lý thuyết Tập hợp

Tìm hiểu về Python set: chúng là gì, cách tạo, khi nào sử dụng, các hàm dựng sẵn và mối liên hệ với các phép toán trong lý thuyết tập hợp.
· 13 phút đọc

Khám phá cùng AI

So sánh Python Sets với Lists và Tuples

List và tuple là các kiểu dữ liệu chuẩn của Python dùng để lưu trữ giá trị theo một chuỗi. Set là một kiểu dữ liệu chuẩn khác của Python cũng dùng để lưu trữ giá trị. Khác biệt lớn là set, không như list hay tuple, không thể chứa nhiều lần cùng một phần tử và lưu trữ các giá trị không có thứ tự.

Ưu điểm của Python Set

Vì set không thể có phần tử trùng lặp, set cực kỳ hữu ích để loại bỏ giá trị trùng lặp khỏi một list hoặc tuple một cách hiệu quả và để thực hiện các phép toán toán học phổ biến như hợp và giao.

Nếu bạn muốn trau dồi kỹ năng Python, hoặc bạn mới bắt đầu, hãy xem lộ trình nghề nghiệp Python Programmer trên DataCamp.

Vậy thì, hãy bắt đầu.

Cách tạo Set trong Python

Set là một tập hợp có thể thay đổi (mutable) gồm các giá trị bất biến (immutable) khác nhau (duy nhất) và không có thứ tự.

Bạn có thể khởi tạo một set rỗng bằng set().

emptySet = set()

Để khởi tạo một set với các giá trị, bạn có thể truyền một list vào set().

dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'])
dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])

Chạy và chỉnh sửa mã từ hướng dẫn trực tuyến này

Chạy mã

Khởi tạo Set

Nếu bạn xem kết quả của các biến dataScientist và dataEngineer ở trên, hãy để ý rằng các giá trị trong set không theo thứ tự đã thêm vào. Đó là vì set là không có thứ tự.

Set chứa giá trị cũng có thể được khởi tạo bằng dấu ngoặc nhọn.

dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}
dataEngineer = {'Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'}

Khởi tạo Set

Lưu ý rằng dấu ngoặc nhọn chỉ có thể dùng để khởi tạo một set khi có giá trị. Hình dưới cho thấy dùng ngoặc nhọn mà không có giá trị là một trong những cách khởi tạo dictionary chứ không phải set.

Khởi tạo Set

Thêm và xóa giá trị khỏi Python Set

Để thêm hoặc xóa giá trị khỏi set, trước hết bạn phải khởi tạo một set.

# Initialize set with values
graphicDesigner = {'InDesign', 'Photoshop', 'Acrobat', 'Premiere', 'Bridge'}

Thêm giá trị vào Python Set

Bạn có thể dùng phương thức add để thêm một giá trị vào set.

graphicDesigner.add('Illustrator')

Thêm giá trị vào Set

Lưu ý quan trọng là bạn chỉ có thể thêm vào set các giá trị bất biến (như string hoặc tuple). Ví dụ, bạn sẽ nhận TypeError nếu cố thêm một list vào set.

graphicDesigner.add(['Powerpoint', 'Blender'])

Thêm giá trị vào Set

Xóa giá trị khỏi Set trong Python

Có vài cách để xóa một giá trị khỏi set.

Cách 1: Bạn có thể dùng phương thức remove để xóa một giá trị khỏi set.

graphicDesigner.remove('Illustrator')

Xóa giá trị khỏi Set

Hạn chế của cách này là nếu bạn cố xóa một giá trị không có trong set, bạn sẽ gặp KeyError.

Xóa giá trị khỏi Set

Cách 2: Bạn có thể dùng phương thức discard để xóa một giá trị khỏi set.

graphicDesigner.discard('Premiere')

Xóa giá trị khỏi Set

Ưu điểm của cách này so với remove là nếu bạn cố xóa một giá trị không thuộc set, bạn sẽ không gặp KeyError. Nếu bạn quen với dictionary, bạn có thể thấy cách này khá giống với phương thức get của dictionary.

Cách 3: Bạn cũng có thể dùng phương thức pop để xóa và trả về một giá trị tùy ý từ set.

graphicDesigner.pop()

Xóa giá trị khỏi Set

Lưu ý quan trọng: phương thức này sẽ phát sinh KeyError nếu set rỗng.

Xóa tất cả giá trị khỏi Python Set

Bạn có thể dùng phương thức clear để xóa tất cả giá trị khỏi set.

graphicDesigner.clear()

Xóa tất cả giá trị khỏi Set

Cập nhật giá trị của Python Set

Phương thức update thêm các phần tử từ một tập vào một set. Nó yêu cầu một đối số duy nhất có thể là set, list, tuple hoặc dictionary. Phương thức .update() tự động chuyển các kiểu dữ liệu khác thành set và thêm chúng vào set. 

Trong ví dụ, chúng ta khởi tạo ba set và dùng hàm update để thêm phần tử từ set2 vào set1 rồi từ set3 vào set1. 

# Initialize 3 sets
set1 = set([7, 10, 11, 13])
set2 = set([11, 8, 9, 12, 14, 15])
set3 = {'d', 'f', 'h'}

# Update set1 with set2
set1.update(set2)
print(set1)

# Update set1 with set3
set1.update(set3)
print(set1)

Cập nhật Set trong Python

Duyệt qua một Python Set

Giống nhiều kiểu dữ liệu chuẩn khác của Python, bạn có thể duyệt qua một set.

# Initialize a set
dataScientist = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}

for skill in dataScientist:
    print(skill)

Duyệt qua Set

Nếu bạn xem kết quả in từng giá trị trong dataScientist, hãy để ý rằng các giá trị được in ra không theo thứ tự đã thêm vào. Đó là vì set là không có thứ tự.

Chuyển Python Set thành các giá trị có thứ tự

Bài hướng dẫn này đã nhấn mạnh rằng set là không có thứ tự. Nếu bạn cần lấy các giá trị từ set theo dạng có thứ tự, bạn có thể dùng hàm sorted, hàm này trả về một list có thứ tự.

type(sorted(dataScientist))

Chuyển Set thành giá trị có thứ tự

Đoạn mã dưới đây xuất ra các giá trị trong set dataScientist theo thứ tự bảng chữ cái giảm dần (trong trường hợp này là Z-A).

sorted(dataScientist, reverse = True)

Chuyển Set thành giá trị có thứ tự

Loại bỏ phần tử trùng lặp khỏi List trong Python

Một phần nội dung ở mục này đã được đề cập trong hướng dẫn 18 Câu hỏi về Python List thường gặp nhất, nhưng điều quan trọng là cần nhấn mạnh set là cách nhanh nhất để loại bỏ phần tử trùng lặp khỏi list. Để chứng minh, hãy xem sự khác biệt hiệu năng giữa hai cách tiếp cận.

Cách tiếp cận 1: Dùng set để loại bỏ phần tử trùng lặp khỏi list.

print(list(set([1, 2, 3, 1, 7])))

Cách tiếp cận 2: Dùng list comprehension để loại bỏ phần tử trùng lặp khỏi list (Nếu bạn muốn ôn lại về list comprehensions, xem hướng dẫn này).

def remove_duplicates(original):
    unique = []
    [unique.append(n) for n in original if n not in unique]
    return(unique)

print(remove_duplicates([1, 2, 3, 1, 7]))

Sự khác biệt hiệu năng có thể đo bằng thư viện timeit cho phép bạn bấm giờ mã Python. Đoạn mã dưới đây chạy mã cho mỗi cách 10000 lần và in ra tổng thời gian tính bằng giây.

import timeit

# Approach 1: Execution time
print(timeit.timeit('list(set([1, 2, 3, 1, 7]))', number=10000))

# Approach 2: Execution time
print(timeit.timeit('remove_duplicates([1, 2, 3, 1, 7])', globals=globals(), number=10000))

Loại bỏ trùng lặp khỏi List

So sánh hai cách tiếp cận này cho thấy dùng set để loại bỏ phần tử trùng lặp hiệu quả hơn. Dù có vẻ chênh lệch thời gian nhỏ, nó có thể tiết kiệm rất nhiều nếu bạn có các list rất lớn.

Các phép toán trên Python Set

Một cách dùng phổ biến của set trong Python là tính các phép toán toán học chuẩn như hợp, giao, hiệu và hiệu đối xứng. Hình dưới minh họa một vài phép toán tiêu chuẩn trên hai set A và B. Phần màu đỏ của mỗi biểu đồ Venn là tập kết quả của phép toán tương ứng.

Phương thức phép toán Set

Python set có các phương thức cho phép bạn thực hiện những phép toán này cũng như các toán tử cho kết quả tương đương.

Trước khi tìm hiểu các phương thức đó, hãy bắt đầu bằng cách khởi tạo hai set dataScientist và dataEngineer.

dataScientist = set(['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'])
dataEngineer = set(['Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'])

union

Phép hợp, ký hiệu dataScientist ∪ dataEngineer, là tập hợp tất cả các giá trị là phần tử của dataScientist, hoặc dataEngineer, hoặc cả hai. Bạn có thể dùng phương thức union để tìm tất cả các giá trị duy nhất trong hai set.

# set built-in function union
dataScientist.union(dataEngineer)

# Equivalent Result
dataScientist | dataEngineer

Tập trả về từ phép hợp có thể hình dung là phần màu đỏ trong biểu đồ Venn dưới đây.

Phương thức phép toán Set

intersection

Phép giao của hai set dataScientist và dataEngineer, ký hiệu dataScientist ∩ dataEngineer, là tập tất cả các giá trị đồng thời thuộc dataScientist và dataEngineer.

# Intersection operation
dataScientist.intersection(dataEngineer)

# Equivalent Result
dataScientist & dataEngineer

intersection

Tập trả về từ phép giao có thể hình dung là phần màu đỏ trong biểu đồ Venn dưới đây.

intersection

Đôi khi bạn muốn đảm bảo hai set không có giá trị chung nào. Nói cách khác, bạn muốn hai set có giao rỗng. Hai set như vậy gọi là tập rời (disjoint). Bạn có thể kiểm tra tập rời bằng phương thức isdisjoint.

# Initialize a set
graphicDesigner = {'Illustrator', 'InDesign', 'Photoshop'}

# These sets have elements in common so it would return False
dataScientist.isdisjoint(dataEngineer)

# These sets have no elements in common so it would return True
dataScientist.isdisjoint(graphicDesigner)

intersection

Bạn có thể thấy trong phần giao thể hiện ở biểu đồ Venn bên dưới rằng hai tập rời dataScientist và graphicDesigner không có giá trị chung nào.

intersection

Difference

Phép hiệu của hai set dataScientist và dataEngineer, ký hiệu dataScientist \ dataEngineer, là tập tất cả các giá trị thuộc dataScientist nhưng không thuộc dataEngineer.

# Difference Operation
dataScientist.difference(dataEngineer)

# Equivalent Result
dataScientist - dataEngineer

difference

Tập trả về từ phép hiệu có thể hình dung là phần màu đỏ trong biểu đồ Venn dưới đây.

difference

Symmetric Difference

Phép hiệu đối xứng của hai set dataScientist và dataEngineer, ký hiệu dataScientist △ dataEngineer, là tập tất cả các giá trị thuộc đúng một trong hai set, nhưng không thuộc cả hai.

# Symmetric Difference Operation
dataScientist.symmetric_difference(dataEngineer)

# Equivalent Result
dataScientist ^ dataEngineer

symmetric_difference

Tập trả về từ phép hiệu đối xứng có thể hình dung là phần màu đỏ trong biểu đồ Venn dưới đây.

symmetric_difference

Set Comprehension

Có thể bạn đã học về list comprehension, dictionary comprehension và generator comprehension. Python cũng có set comprehension. Set comprehension rất giống các loại trên. Set comprehension trong Python có thể được viết như sau:

{skill for skill in ['SQL', 'SQL', 'PYTHON', 'PYTHON']}

Set Comprehension

Kết quả ở trên là một set gồm 2 giá trị vì set không thể chứa nhiều lần cùng một phần tử.

Ý tưởng đằng sau việc dùng set comprehension là giúp bạn viết và suy nghĩ trong mã theo cách tương tự như làm toán bằng tay.

{skill for skill in ['GIT', 'PYTHON', 'SQL'] if skill not in {'GIT', 'PYTHON', 'JAVA'}}
 

Đoạn mã trên tương tự với phép hiệu giữa các set mà bạn đã học trước đó. Nó chỉ trông hơi khác một chút.

Kiểm tra tư cách thành viên (membership)

Bài kiểm tra membership kiểm tra xem một phần tử cụ thể có nằm trong một chuỗi hay không, như string, list, tuple hoặc set. Một trong những ưu điểm chính của việc dùng set trong Python là chúng được tối ưu hóa cao cho việc kiểm tra membership. Ví dụ, set thực hiện kiểm tra membership hiệu quả hơn nhiều so với list. Nếu bạn có nền tảng khoa học máy tính, đó là vì độ phức tạp thời gian trung bình của kiểm tra membership trong set là O(1) so với O(n) đối với list.

Đoạn mã dưới đây minh họa kiểm tra membership dùng list.

# Initialize a list
possibleList = ['Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala']

# Membership test
'Python' in possibleList

Kiểm tra membership

Có thể làm điều tương tự với set. Chỉ là set hiệu quả hơn.

# Initialize a set
possibleSet = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS', 'Java', 'Spark', 'Scala'}

# Membership test
'Python' in possibleSet

Kiểm tra membership

Vì possibleSet là một set và giá trị 'Python' là phần tử của possibleSet, có thể ký hiệu là 'Python' ∈ possibleSet.

Nếu bạn có một giá trị không thuộc set, như 'Fortran', sẽ được ký hiệu là 'Fortran' ∉ possibleSet.

Tập con (Subset)

Một ứng dụng thực tế của việc hiểu membership là tập con.

Trước tiên, hãy khởi tạo hai set.

possibleSkills = {'Python', 'R', 'SQL', 'Git', 'Tableau', 'SAS'}
mySkills = {'Python', 'R'}
 

Nếu mọi giá trị của set mySkills cũng là giá trị của set possibleSkills, thì nói rằng mySkills là tập con của possibleSkills, viết dưới dạng toán học mySkills ⊆ possibleSkills.

Bạn có thể kiểm tra xem một set có phải là tập con của set khác hay không bằng phương thức issubset.

mySkills.issubset(possibleSkills)

Tập con

Vì phương thức trả về True trong trường hợp này, đây là một tập con. Trên biểu đồ Venn dưới đây, hãy để ý rằng mọi giá trị của set mySkills cũng là giá trị của set possibleSkills.

Tập con

Frozenset

Bạn có thể đã gặp list và tuple lồng nhau.

# Nested Lists and Tuples
nestedLists = [['the', 12], ['to', 11], ['of', 9], ['and', 7], ['that', 6]]
nestedTuples = (('the', 12), ('to', 11), ('of', 9), ('and', 7), ('that', 6))

Frozensets

Vấn đề với set lồng nhau là bạn thường không thể có set lồng nhau trong Python, vì set không thể chứa các giá trị có thể thay đổi, bao gồm cả set.

Frozensets

Đây là một tình huống mà bạn có thể muốn dùng frozenset. Frozenset rất giống set ngoại trừ việc frozenset là bất biến.

Bạn tạo frozenset bằng frozenset().

# Initialize a frozenset
immutableSet = frozenset()

Frozensets

Bạn có thể tạo set lồng nhau nếu dùng frozenset tương tự đoạn mã dưới đây.

nestedSets = set([frozenset()])

Frozensets

Lưu ý quan trọng rằng một nhược điểm lớn của frozenset là vì chúng bất biến, nghĩa là bạn không thể thêm hoặc xóa giá trị.

Kết luận

Python set cực kỳ hữu ích để loại bỏ giá trị trùng lặp khỏi một tập hợp như list và để thực hiện các phép toán toán học phổ biến như hợp và giao. Một số thách thức mọi người hay gặp là khi nào dùng các kiểu dữ liệu khác nhau. Ví dụ, nếu bạn chưa chắc khi nào nên dùng dictionary thay vì set, tôi khuyến khích bạn thử chế độ luyện tập hằng ngày của DataCamp. Nếu bạn có câu hỏi hoặc ý kiến về bài hướng dẫn, hãy để lại bình luận bên dưới hoặc liên hệ qua Twitter.

Chủ đề