# data[].attributes.body
1.3 Các phép toán trong tập hợp

Các tập hợp có lợi thế hơn các cấu trúc dữ liệu khác ở chỗ nó thực hiện được các phép toán tập hợp như hợp, hiệu, giao… Để mô tả dễ hiểu hơn, chúng ta có hai tập hợp art_friends và science_friends là tập hợp các bạn trong lớp Mỹ thuật và tập hợp các bạn trong lớp Khoa học.

art_friends = {"Rolf", "Anne", "Jen"}
science_friends = {"Jen", "Charlie"}

Các phép toán được mô tả như hình sau:

1.3.1 Phép hợp (Union)

Hợp của hai tập hợp cho kết quả là tất cả các phần tử trong hai tập hợp, chú ý phần tử nào lặp lại sẽ chỉ xuất hiện 1 lần trong tập kết quả. Trong Python, để thực hiện phép hợp, chúng ta sử dụng phương thức .union(). Chú ý, sử dụng tập hợp nào trước cũng cho kết quả như nhau, art_friends.union(science_friends) cũng cho kết quả như science_friends.union(art_friends).

art_friends = {"Rolf", "Anne", "Jen"}
science_friends = {"Jen", "Charlie"}
all_friends = art_friends.union(science_friends)
print(all_friends) # Kết quả {'Rolf', 'Anne', 'Jen', 'Charlie'}

Chú ý, “Jen” có mặt trong cả hai lớp nhưng với tập kết quả cuối cùng thì “Jen” chỉ xuất hiện 1 lần.

1.3.2 Phép trừ (Difference)

Hiệu của một tập A trừ đi một tập B cho kết quả là tất các phần tử thuộc A nhưng không thuộc B. Sử dụng phương thức .difference() để thực hiện phép trừ hai tập hợp.

art_friends = {"Rolf", "Anne", "Jen"}
science_friends = {"Jen", "Charlie"}
art_but_not_science = art_friends.difference(science_friends)
science_but_not_art = science_friends.difference(art_friends)

print(art_but_not_science) # Kết quả {'Rolf', 'Anne'}
print(science_but_not_art) # Kết quả {'Charlie'}

Xem tiếp...

Trong ví dụ trên, tập hợp art_but_not_science chứa các bạn học lớp Mỹ thuật nhưng không học lớp Khoa học, chú ý “Jen” học cả hai lớp nên không có mặt trong tập hợp này.

1.3.3 Hiệu đối xứng của hai tập hợp (Symmetric difference)

Hiệu đối xứng của hai tập A và B được kết quả là tập hợp các phần tử thuộc cả A và B nhưng không đồng thời thuộc cả tập A và B. Phương thức .symmetric_difference() cho kết quả là hiệu đối xứng của hai tập hợp. Chú ý, do tính chất đối xứng nên art_friends.symmetric_difference(science_friends) và science_friends.symmetric_difference(art_friends) cho kết quả như nhau.

art_friends = {"Rolf", "Anne", "Jen"}
science_friends = {"Jen", "Charlie"}

not_in_both_1 = art_friends.symmetric_difference(science_friends)
print(not_in_both_1) # Kết quả {'Rolf', 'Charlie', 'Anne'}

not_in_both_2 = science_friends.symmetric_difference(art_friends)
print(not_in_both_2) # Kết quả {'Rolf', 'Anne', 'Charlie'}

Xem tiếp...

1.3.4 Phép giao (Intersection)

Phép giao hai tập hợp cho kết quả là các phần tử đồng thời thuộc cả hai tập hợp. Trong Python sử dụng phương thức .intersection() để thực hiện phép giao, chú ý tập hợp nào đứng trước cũng được, do đó kết quả art_friends.intersection(science_friends) và science_friends.intersection(art_friends) là như nhau.

art_friends = {"Rolf", "Anne", "Jen"}
science_friends = {"Jen", "Charlie"}

art_and_science = art_friends.intersection(science_friends)
print(art_and_science) # Kết quả là {"Jen"}

Tập hợp art_and_science chứa các bạn học đồng thời cả lớp Mỹ thuật và lớp Khoa học, do đó kết quả chỉ có “Jen” học cả hai lớp này.

1.3.5 Thay đổi tập hợp dựa trên phép toán tập hợp

Trong phần trước chúng ta đã biết đến phương thức .update() để thêm nhiều phần tử vào một tập hợp. Dựa vào các phép toán tập hợp, Python cung cấp một số các phương thức khác để thay đổi tập hợp như sau:

.difference_update()

Phương thức này là sự kết hợp của .difference() và .update(). Nó thực hiện phép trừ tập hợp trước, được kết quả như thế nào sẽ cập nhật vào tập hợp đích.

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

A.difference_update(B)
print(A) # Kết quả {1, 2}

.symmetric_difference_update()

Phương thức này là sự kết hợp của .symmetric_difference() và .update(). Nó thực hiện phép trừ đối xứng 2 tập hợp trước, được kết quả như thế nào sẽ cập nhật vào tập hợp đích.

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

A.symmetric_difference_update(B)
print(A) # Kết quả là {1, 2, 5, 6}

.intersection_update()

Tương tự, Python thực hiện .intersection() trước sau đó thực hiện .update():

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

A.intersection_update(B)
print(A) # Kết quả là {3, 4}

1.3.6 Một số các phép toán khác

.isdisjoint() Trả về True nếu hai tập hợp không giao nhau, tức là hai tập hợp không có phần tử chung.

A = {1, 2, 3, 4}
B = {3, 4, 5, 6}

print(not A.isdisjoint(B)) # Kết quả là True

Ở đây, chúng ta sử dụng toán tử logic not, để thực hiện trả về True khi hai tập giao nhau, nghe nó thuận tai hơn :D.

.issubset() Trả về True nếu tập này còn tập con của tập đích (tập trong ngoặc).

A = {3, 4}
B = {3, 4, 5, 6}

print(A.issubset(B)) # Kết quả là True

.issuperset() Trả về True nếu tập này là tập cha của tập đích (tập trong ngoặc).

A = {3, 4}
B = {3, 4, 5, 6}

print(A.issuperset(B)) # Kết quả là False

Ngoài ra chúng ta có thể sử dụng các ký hiệu phép toán so sánh thông thường để kiểm tra xem là tập con, tập cha hay hai tập bằng nhau với >, >=, ==, <, <=.

A = {3, 4}
B = {3, 4, 5, 6}

print(A.issubset(B)) # Kết quả là True

# data[].attributes.body
Set cũng là 1 cấu trúc dữ liệu để lưu một danh sách các phần tử cùng kiểu dữ liệu, trong đó các phần tử không được trùng nhau. Ví dụ như array có thể có các phần tử trùng nhau như {1, 2, 1, 1, 2} nhưng set thì chỉ chứa các phần tử khác nhau {1, 2}

# data[].attributes.body
Thay đổi tập hợp

Các phần tử trong tập hợp có thể thêm hoặc loại bỏ. Python hỗ trợ rất nhiều các phương thức để thực hiện thao tác thay đổi tập hợp.

1.2.1 Phương thức .add()

Phương thức sử dụng để thêm một phần tử vào tập hợp.

Ví dụ:

friends = {"Rolf","Bob","Anne"}
friends.add("Jen")
print(friends) # Kết quả là {"Bob","Jen","Anne","Rolf"}

Chú ý, kết quả có thể khác đi do Set không sắp xếp các phần tử theo một trật tự nào cả.

1.2.2 Phương thức .remove()

Loại bỏ một phần tử trong tập hợp.

Ví dụ:

friends = {"Rolf","Bob","Anne"}
friends.remove("Anne")
print(friends) # Kết quả là {"Rolf","Bob"}
friends.remove("Jen")
print(friends) # Kết quả là lỗi KeyError: "Jen"

Khi loại bỏ một phần tử, nếu phần tử đó không tồn tại trong tập hợp, chương trình sẽ dừng và một thông báo lỗi KeyError xuất hiện.

1.2.3 Phương thức .discard()

Giống như phương thức .remove() loại bỏ phần tử trong tập hợp, tuy nhiên nếu phần tử đó không tồn tại thì nó không báo lỗi gì cả.

friends = {"Rolf","Bob","Anne"}
friends.discard("Anne")
print(friends) # Kết quả là {"Rolf","Bob"}
friends.discard("Jen")
print(friends) # Kết quả là {"Rolf","Bob"}

1.2.4 Phương thức .pop()

Loại bỏ một phần tử ngẫu nhiên khỏi tập hợp.

friends = {"Rolf","Bob","Anne"}
friends.pop()
print(friends) # Kết quả là {"Bob","Rolf"}

Bạn cần chú ý về thứ tự các phần tử trong tập hợp, nó không được sắp xếp theo bất kỳ quy tắc nào.

1.2.5 Phương thức .clear()

Loại bỏ tất cả các phần tử trong tập hợp, khi đó tập hợp được gọi là tập rỗng.

friends = {"Rolf","Bob","Anne"}
friends.clear()
print(friends) # Kết quả là set()

1.2.6 Phương thức .update()

Phương thức .add() ở trên chỉ thêm được 1 phần tử vào tập hợp với 1 câu lệnh, để thêm nhiều phần tử, chúng ta sử dụng .update(). Chú ý, đầu vào của .update() có thể là một Set, một List hoặc một Tuple.

friends = {"Rolf","Bob","Anne"}
friends.update(["Jen","Charlie"],{"Jonhny", "Sara"},("Laura","Elite"))
print(friends) # Kết quả là {'Anne', 'Laura', 'Elite', 'Rolf', 'Jonhny', 'Charlie', 'Bob', 'Sara', 'Jen'}

Kết quả của bạn có thể có thứ tự khác đi, một chú ý nữa là không sử dụng chuỗi để cập nhập vào tập hợp mà các phần tử là chuỗi bởi vì chuỗi sẽ được coi là một danh sách các ký tự, ví dụ:

friends = {"Rolf","Bob","Anne"}
friends.update("Jen")
print(friends) # Kết quả là {'n', 'e', 'Rolf', 'Bob', 'Anne', 'J'}

Không như mong đợi phải không, bạn có thể sử dụng phương thức .add() hoặc có thể chuyển chuỗi thành Set, List hoặc Tuple có 1 phần tử:

friends = {"Rolf","Bob","Anne"}
friends.update(("Jen",))
# hoặc
friends.update(["Jen"])
# hoặc
friends.update({"Jen"})

Có một số phương thức update khác như .difference_update(), .symmetric_difference_update() hay .intersection_update() nó có liên quan đến các phép toán trong tập hợp nên sẽ trình bày ở phần tiếp theo.

# data[].attributes.body
Toán tập hợp hay lý thuyết tập hợp là một trong những phần quan trọng của Toán học mà Khoa học dữ liệu (data science) và Machine Learning sử dụng kiến thức Toán rất nhiều, do vậy toán tập hợp trong Python là một phần không thể thiếu. Ngay từ đầu Python đã được phát triển cho mục đích Khoa học và Giáo dục, do vậy bạn có thể thấy các thiết kế mang hơi hướng Khoa học.

Tập hợp cũng là một nhóm các dữ liệu giống như với List và Tuple nhưng nó lại được xây dựng sẵn các phép toán tập hợp, do vậy tập hợp sẽ được sử dụng khi chương trình của bạn cần các phép toán tập hợp như .union(), .difference(), .intersection()… Để lựa chọn cấu trúc dữ liệu phù hợp, bạn cần nắm rõ những đặc điểm của từng loại, ở đây Set có những đặc điểm mà tôi đã đưa ra ở phần đầu, dưới đây chỉ nhắc lại:

Set có các phần tử là không được thay đổi, do vậy khả năng tìm dữ liệu sẽ nhanh hơn.

Set cần thiết cho các logic liên đến các cặp (key:value) trong cấu trúc Dictionary của Python.

Các phần tử là duy nhất, do đó nếu bạn có một dữ liệu tương tự thì Set là một lựa chọn.