Python Set 集合:自動去重與無序集合實戰

Python Set 集合是以大括號 {} 建立的無序容器,最大的特點是自動去除重複元素,確保每個值只出現一次。本文全攻略 Set 的建立語法、add、remove、discard 等常用方法、集合運算(聯集、交集、差集、對稱差),以及 frozenset 不可變集合、Set Comprehension 生成式與實戰去重應用,讓你徹底掌握 Python Set 的核心技巧。

Cinematic visualization of Python set as a glowing alchemical crucible filtering and purifying duplicate elements into unique glowing orbs, dark forge environment with deep amber light and dramatic shadows, mystical deduplication process, 16:9

什麼是 Set 集合?

Set(集合)是 Python 的內建資料型別,使用大括號 {} 建立,元素之間以逗號分隔。它有兩個核心特性:無序(unordered)唯一性(unique)——Set 不保留元素的插入順序,也不允許重複值,加入已存在的元素時會自動忽略。

可以把 Set 想像成一個只收「不重複票」的票箱:你投入再多同樣的票,箱子裡也只保留一張。這讓 Set 天生適合做去重(deduplication)、成員測試(membership test),以及數學集合運算如聯集、交集、差集。

Set 的成員測試速度比 List 快許多(底層使用雜湊表),因此當你需要頻繁執行 x in collection 的查詢時,Set 是比 List 更好的選擇。

核心語法:建立與基本操作

# === 建立 Set ===
# 方式一:大括號,元素直接列出
fruits = {'apple', 'banana', 'orange', 'apple'}  # 重複的 apple 自動去除
print(fruits)   # {'apple', 'banana', 'orange'}(順序不保證)

# 方式二:set() 轉換其他序列(最常用的去重技巧)
nums_with_dup = [1, 2, 2, 3, 3, 3, 4]
unique_nums = set(nums_with_dup)
print(unique_nums)  # {1, 2, 3, 4}

# 建立空 Set(注意:{} 是空 Dict,不是空 Set!)
empty_set = set()   # ✅ 正確
wrong = {}          # ❌ 這是空字典,不是空集合

print(type(empty_set))  # 
print(type(wrong))      # 
建立空 Set 必須用 set(),不能用 {}{} 在 Python 中代表空字典(dict),這是初學者最常踩的陷阱。
# === 新增與刪除元素 ===
tickers = {'AAPL', 'TSLA', 'GOOGL'}

# add():新增單一元素(重複加入不報錯,靜默忽略)
tickers.add('MSFT')
tickers.add('AAPL')    # AAPL 已存在,Set 不變
print(tickers)         # {'AAPL', 'TSLA', 'GOOGL', 'MSFT'}

# remove():刪除元素,若不存在則拋出 KeyError
tickers.remove('TSLA')

# discard():刪除元素,不存在時靜默忽略(更安全)
tickers.discard('NVDA')   # NVDA 不在集合中,不報錯

# pop():隨機移除並回傳一個元素(因為 Set 無順序)
removed = tickers.pop()
print(f'移除了:{removed}')

# clear():清空整個 Set
tickers.clear()
print(tickers)   # set()
日常使用建議優先選 discard() 而非 remove()——前者在元素不存在時安靜忽略,程式不會崩潰;後者若 Key 不存在會拋出 KeyError
# === 成員測試與長度 ===
watchlist = {'AAPL', 'TSLA', 'GOOGL', 'MSFT'}

print('AAPL' in watchlist)    # True
print('NVDA' in watchlist)    # False
print('NVDA' not in watchlist)  # True
print(len(watchlist))         # 4

規則與注意事項

規則 正確範例 錯誤範例
Set 元素必須可雜湊(hashable) {1, 'hello', (1, 2)} {[1, 2], 3} → TypeError
建立空 Set 用 set(),不用 {} s = set() s = {}(這是空 Dict)
Set 無索引,不支援 s[0] 存取 for item in s:(迭代) s[0] → TypeError
重複元素自動忽略,不報錯 s.add('已存在的值')(靜默) 誤以為 add 重複值會拋例外
discard 比 remove 更安全 s.discard('不存在的值') s.remove('不存在的值') → KeyError

常見錯誤與防呆

錯誤一:用 {} 建立空 Set

# ❌ 錯誤寫法(這是空字典,不是空集合)
s = {}
print(type(s))  # 

# ✅ 正確寫法
s = set()
print(type(s))  # 

錯誤二:把 List 放入 Set(List 不可雜湊)

# ❌ 錯誤寫法(TypeError: unhashable type: 'list')
s = {[1, 2], [3, 4]}

# ✅ 正確寫法:List 改用 Tuple 作為集合元素
s = {(1, 2), (3, 4)}
print(s)  # {(1, 2), (3, 4)}

錯誤三:試圖用索引存取 Set 元素

# ❌ 錯誤寫法(TypeError: 'set' object is not subscriptable)
s = {10, 20, 30}
print(s[0])

# ✅ 正確做法:用 for 迭代,或先轉為 List 再取索引
for item in s:
    print(item)

# 或轉成 list 再取值(注意順序不保證)
s_list = list(s)
print(s_list[0])

進階用法

集合運算:聯集、交集、差集、對稱差

Set 最強大的地方在於支援數學意義上的集合運算,讓資料比較工作只需一行程式碼即可完成。

A = {'AAPL', 'TSLA', 'GOOGL', 'MSFT'}   # 自選股A
B = {'TSLA', 'MSFT', 'NVDA', 'META'}    # 自選股B

# 聯集(union):兩個集合所有不重複元素
print(A | B)          # {'AAPL', 'TSLA', 'GOOGL', 'MSFT', 'NVDA', 'META'}
print(A.union(B))     # 同上

# 交集(intersection):兩個集合共有的元素
print(A & B)          # {'TSLA', 'MSFT'}
print(A.intersection(B))  # 同上

# 差集(difference):在 A 中但不在 B 中的元素
print(A - B)          # {'AAPL', 'GOOGL'}
print(A.difference(B))  # 同上

# 對稱差(symmetric_difference):只在其中一個集合的元素
print(A ^ B)          # {'AAPL', 'GOOGL', 'NVDA', 'META'}
print(A.symmetric_difference(B))  # 同上

快速去重:List 轉 Set 再轉回

最常見的 Set 使用場景:將含有重複項目的 List 去重,保留唯一值。這個技巧只需一行,且效能遠優於手動用 for 迴圈判斷。

# 情境:量化回測中,過濾重複的交易信號日期
trade_dates = ['2024-01-03', '2024-01-05', '2024-01-03',
               '2024-01-08', '2024-01-05', '2024-01-10']

unique_dates = list(set(trade_dates))  # 去重後轉回 List
unique_dates.sort()                    # Set 無序,需手動排序
print(unique_dates)
# ['2024-01-03', '2024-01-05', '2024-01-08', '2024-01-10']

# 快速確認是否有重複
has_dup = len(trade_dates) != len(set(trade_dates))
print(f'有重複?{has_dup}')  # 有重複?True

Set Comprehension 集合生成式

與 List Comprehension 語法相似,Set Comprehension 使用大括號,一行建立含有特定條件的集合,並自動去除重複。

# 取 1~20 中所有偶數,並自動去重
even_set = {x for x in range(1, 21) if x % 2 == 0}
print(even_set)  # {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}

# 取字串中所有不重複的字母(自動小寫化)
sentence = 'Python is Fun'
unique_chars = {c.lower() for c in sentence if c != ' '}
print(unique_chars)  # {'p', 'y', 't', 'h', 'o', 'n', 'i', 's', 'f', 'u'}

煉金坊小叮嚀

Set 是四大基礎資料結構中最容易被忽略,卻在特定場景極為好用的一個!我在量化交易開發中,最常用它來過濾重複的信號、快速比對兩個觀察名單的差異。記住一個選用法則:需要去重或快速成員查詢,用 Set;需要保留順序或索引存取,用 List。 另外,別忘了空集合只能用 set() 建立,{} 是字典,這個細節很多人寫了很久還是會搞混。Set 的集合運算(&、|、-)更是資料比對的神器,一行程式碼就能完成以前需要雙層迴圈才能做到的事。

張貼留言

較新的 較舊