Python set

Python 教學 8 – Python Set Type: Set, Frozenset

Python set 和 frozenset 常用來表示一群不重複 element 的集合,這篇文章就來介紹一下 Python set 和 frozenset。

1. 特性

1.1 set, frozenset 的共通特性

  • object 內的 element 不會重複
  • 沒有順序性

1.2 set, frozenset 的差別

set 和 frozenset 的差別其實就像 list 和 tuple 一樣,set 是 mutable,frozenset 是 immutable,宣告後就不能對其做其他操作。

my_set = set(range(3))
my_set.add(5)
print(my_set)
{0, 1, 2, 5}

my_frozenset = frozenset(range(3))
my_frozenset.add(5)
AttributeError: 'frozenset' object has no attribute 'add'

2. 宣告

2.1 宣告 set

2.1.1 braces: {}

如果要宣告有 elements 的 set 的話,可以用大括號把 elements 包在裡面,但如果要宣告的 set 是空的話,就需要用 set type constructor,否則會變成 dict。

my_set = {1, 1, 2, 2, 3, 3}
print(type(my_set))
<class 'set'>
# set 會自動把重複項目刪除
print(my_set)
{1, 2, 3}

empty_dict = {}
print(type(empty_dict))
<class 'dict'>
print(empty_dict)
{}

empty_set = set()
print(type(empty_set))
<class 'set'>
print(empty_set)
set()

2.1.2 Set Comprehension

Comprehension 是 Python 中特殊的表示法,詳細介紹可以參考:Python Comprehension 語法 – List Comprehension, Set Comprehension, Dict Comprehension

Set Comprehension 的語法:

{expression for item in iterable (if condition)}

至於 iterable 的定義,可以參考這篇:Python Iterable Objects 介紹

my_set = {i for i in range(5)}
print(type(my_set))
<class 'set'>
print(my_set)
{0, 1, 2, 3, 4}

my_set = {i * 2 for i in range(5)}
print(my_set)
{0, 2, 4, 6, 8}

my_set = {s for s in 'Hello World'}
print(my_set)
{'e', 'H', 'W', 'o', 'r', ' ', 'd', 'l'}

2.1.3 type constructor: set()

可以用 set 的 type constructor 來宣告 set

class set([iterable])

可將 iterable object 轉換成 set,但 iterable object 的每個 item 都必須是 hashable object,否則無法轉成 set:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() method). 資料來源:Python document
my_str = 'hi'
print(set(my_str))
{'h', 'i'}

my_list = [1, 2]
print(set(my_list))
{1, 2}

my_tuple = (1, 2)
print(set(my_tuple))
{1, 2}

# set 不保證順序
my_dict = { 'name': 'jimmy', 'city': 'taipei' }
print(set(my_dict))
{'city', 'name'}
print(set(my_dict.values()))
{'taipei', 'jimmy'}

my_set = {1, 2}
print(set(my_set))
{1, 2}

my_list = [[1], [2]]
print(set(my_list))
TypeError: unhashable type: 'list'

2.2 宣告 frozenset – frozenset type constructor

宣告 frozenset 只有一種方法,就是用 frozenset 的 type constructor。

class frozenset([iterable])

和 set type constructor 一樣,iterable object 的每個 item 都必須是 hashable object,否則無法轉成 set

my_str = 'hi'
print(frozenset(my_str))
frozenset({'h', 'i'})

my_list = [1, 2]
print(frozenset(my_list))
frozenset({1, 2})

my_tuple = (1, 2)
print(frozenset(my_tuple))
frozenset({1, 2})

# frozenset 不保證順序
my_dict = { 'name': 'jimmy', 'city': 'taipei' }
print(frozenset(my_dict))
frozenset({'name', 'city'})
print(frozenset(my_dict.values()))
frozenset({'jimmy', 'taipei'})

my_frozenset = {1, 2}
print(frozenset(my_frozenset))
frozenset({1, 2})

my_list = [[1], [2]]
print(frozenset(my_list))
TypeError: unhashable type: 'list'

3. Common Operation

因為 set 和 frozenset 是無順序性的,所以每個 element 不會有 index,也不能用 slice 的方法取得 set 或 frozenset 的部分片段,只能判斷某 element 是否存在於 set 或 frozenset。

3.1 in

用來判斷某 element 是否存在 set 或 frozenset 中

my_set = {1, 3, 7}
print(3 in my_set)
True
print(5 in my_set)
False

my_frozenset = frozenset({1, 3, 7})
print(3 in my_frozenset)
True
print(5 in my_frozenset)
False

3.2 not in

跟 in 相反,用來判斷這個 element 是否不在 set 或 frozenset 裡:

my_set = {1, 3, 7}
print(3 not in my_set)
False
print(5 not in my_set)
True

my_frozenset = frozenset({1, 3, 7})
print(3 not in my_frozenset)
False
print(5 not in my_frozenset)
True

3.3 len()

用來回傳 set 或 frozenset 的長度

my_set = {1, 3, 7}
print(len(my_set))
3

my_frozenset = frozenset({1, 3, 7})
print(len(my_frozenset))
3

4. 操作 set

4.1 set.add(element)

將某 element 加到 set 裡面,如果該 element 已經在 set 裡,則自動忽略

my_set = {1, 3, 7}
my_set.add(9)
print(my_set)
{1, 3, 9, 7}
my_set.add(1)
print(my_set)
{1, 3, 9, 7}

4.2 set.remove(element)

移除 set 中的某個 element,如果該 element 本來就不在 set 裡,會 raise  KeyError

my_set = {1, 3, 7}
my_set.remove(3)
print(my_set)
{1, 7}
my_set.remove(5)
KeyError: 5

4.3 set.discard(element)

移除 set 中的某個 element,和 remove 的差別在於,如果該 element 不在 set 的話,不會噴錯

my_set = {1, 3, 7}
my_set.discard(3)
print(my_set)
{1, 7}
my_set.discard(5)
print(my_set)
{1, 7}

4.4 set.pop()

pop 會隨機移除 set 的某個 element,如果該 set 是空的,會 raise KeyError

my_set = {1, 3, 7}
print(my_set.pop())
1
print(my_set)
{3, 7}

my_set = set()
print(my_set.pop())
KeyError: 'pop from an empty set'

4.5 set.clear()

清空 set 裡的所有 elements

my_set = {1, 3, 7}
my_set.clear()
print(my_set)
set()

5. 集合

set 還有一個很常的應用場景是用在數學的集合上

5.1 intersection – 交集

以下兩個語法都可以取到兩個 set 的交集,也就是兩個 set 都出現的 element

set_a.intersection(set_b)
set_a & set_b
my_set_a = {1, 3, 6, 8, 10}
my_set_b = {1, 2, 6, 8}

print(my_set_a.intersection(my_set_b))
{8, 1, 6}
print(my_set_a & my_set_b)
{8, 1, 6}

5.2 union – 聯集

以下兩個語法都可以取到兩個 set 的聯集,也就是兩個 set 只要出現過一次的 element

set_a.union(set_b)
set_a | set_b
my_set_a = {1, 3, 6, 8, 10}
my_set_b = {1, 2, 6, 8}

print(my_set_a.union(my_set_b))
{1, 2, 3, 6, 8, 10}
print(my_set_a | my_set_b)
{1, 2, 3, 6, 8, 10}

5.3 difference – 差集

以下兩個語法都可以取到 set_a 和 set_b 的差集,也就是 set_a 把 set_a 和 set_b 的交集刪除

set_a.difference(set_b)
set_a - set_b
my_set_a = {1, 3, 6, 8, 10}
my_set_b = {1, 2, 6, 8}

print(my_set_a.difference(my_set_b))
{10, 3}
print(my_set_a - my_set_b)
{10, 3}

5.4 symmetric_difference – 對稱差集

以下兩個語法都可以取到 set_a 和 set_b 的對稱差集,也就是 set_a 和 set_b 的聯集把 set_a 和 set_b 的交集刪除

set_a.symmetric_difference(set_b)
set_a ^ set_b
my_set_a = {1, 3, 6, 8, 10}
my_set_b = {1, 2, 6, 8}

print(my_set_a.symmetric_difference(my_set_b))
{2, 3, 10}
print(my_set_a ^ my_set_b)
{2, 3, 10}

5.5 subset, superset

可以用 issubset 和 issuperset 來判斷兩個 set 是否互為 subset 或 superset

set_a.issubset(set_b)
set_a <= set_b

set_a.issuperset(set_b)
set_a >= set_b
my_set_a = {1, 3, 6, 8}
my_set_b = {1, 3, 6}

print(my_set_a.issubset(my_set_b))
False
print(my_set_b.issubset(my_set_a))
True

print(my_set_a.issuperset(my_set_b))
True
print(my_set_b.issuperset(my_set_a))
False

參考資料

[Python] 學習使用集合(Set) – 通訊雜記
集合set – Python 教學| STEAM 教育學習網
Built-in Types — Python 3.11.5 documentation

如果覺得我的文章有幫助的話,歡迎幫我的粉專按讚哦~謝謝你!

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top