HOWTO · Python

如何在 Python 中比較串列

根據是否在意順序和重複次數,使用 `==`、`Counter`、集合操作或保留順序的串列推導式來比較 Python 串列。

本頁內容

比較兩個 Python 串列時,先確定順序和重複次數是否有意義。精確且有序的相等性使用 ==;忽略順序但保留重複次數時使用 Counter;只關心唯一值的交集或差集時使用 set();結果必須按輸入串列順序排列時使用串列推導式。

下文所有範例都只使用 Python 標準函式庫,並已用 Python 3.14.7 驗證。除非專案另有相容性要求,這些方法同樣適用於仍受支援的較早 Python 3 版本。

目標 建議方法 順序是否重要 重複次數是否重要 元素要求
測試完全相等的串列 left == right 是 是 元素必須支援相等比較
測試無序相等性 Counter(left) == Counter(right) 否 是 元素必須可雜湊
比較唯一值 set() 操作 否 否 元素必須可雜湊
按串列順序保留共同元素 串列推導式加成員集合 只影響輸出順序 保留被掃描串列中的重複項 成員值必須可雜湊
在交集或差集中保留數量 Counter 操作 否 是 元素必須可雜湊

這些方法回答的是不同問題,並不是在爭奪同一個「最快」方案。相等比較會傳回一個布林值,集合和 Counter 操作會建立類似集合的結果,而推導式能控制新串列的形狀和順序。先決定所需語義再考慮效能;僅為加快比較而更換表示方式,也可能改變答案。

使用 == 比較完全有序的串列

Python 的串列相等比較會從左到右比較對應元素。只有長度相同、每個位置的值相等且順序一致時,兩個串列才相等。當串列表示處理步驟、排名結果或有序事件等序列時,這是最清晰的選擇。

"""Verify that list equality considers both values and order."""

first = [1, 2, 3]
same = [1, 2, 3]
reordered = [3, 2, 1]

print(first == same)
print(first == reordered)
True
False

第二個比較即使兩個串列包含相同的唯一值,結果仍為 False。直接相等比較也適用於巢狀串列等不可雜湊元素,因為它不會建立雜湊表。

元素比較仍遵循各個值自身的相等規則。例如,比較自訂物件組成的串列可能會呼叫物件的 __eq__ 實作。此方法不會遞迴指出巢狀結構在哪一處不同;它只傳回最終的布林結果。

使用 Counter 比較保留重複次數的無序串列

當需要忽略順序但保留每個值出現的次數時,請使用 collections.Counter。Counter 將每個可雜湊項目對應為計數,因此只有兩個串列包含相同值且每個值的出現次數相同時,兩個計數器才相等。

"""Compare unordered lists with and without duplicate multiplicity."""

from collections import Counter

left = [1, 2, 2, 3]
reordered = [3, 2, 1, 2]
fewer_duplicates = [3, 2, 1]

print(Counter(left) == Counter(reordered))
print(Counter(left) == Counter(fewer_duplicates))
print(set(left) == set(fewer_duplicates))
True
False
True

最後兩行揭示了一個重要邊界:Counter 能發現少了第二個 2,而集合比較會報告相等,因為集合會捨棄重複項。重複值有意義時,不要用 set(left) == set(right) 代替。

內建 sorted() 還提供了保留重複次數的另一種選擇:sorted(left) == sorted(right),但前提是串列中的所有值可以彼此排序。它還會配置排序後的串列並執行排序,因此 Counter 通常能更直接地表達無序頻率相等性。若之後還需要排序後的序列,排序仍然有用。

使用 set() 比較唯一值、交集和差集

只關心不同值時,將串列轉換為集合。集合交集(&)傳回同時存在於兩個輸入中的值。差集(-)具有方向性,而對稱差集(^)傳回只出現在一側的值。

下面經過驗證的範例只對展示出的集合結果排序,以使輸出具有確定性。比較本身並不會為集合賦予順序。

集合轉換適合需要大量成員查詢的任務,因為它會一次建立查詢結構;但輸出必須保留位置或重複次數時並不適合。也不要依賴集合的列印順序;只有在值能夠相互排序且需要穩定展示時,才明確排序。

"""Verify unique-value, order-preserving, and multiplicity-aware differences."""

from collections import Counter

left = [1, 2, 2, 3, 4]
right = [2, 3, 3, 5]
left_set = set(left)
right_set = set(right)

print(sorted(left_set & right_set))
print(sorted(left_set - right_set))
print(sorted(right_set - left_set))

right_members = set(right)
print([item for item in left if item in right_members])

left_counts = Counter(left)
right_counts = Counter(right)
print(sorted((left_counts & right_counts).elements()))
print(sorted((left_counts - right_counts).elements()))
print(sorted((right_counts - left_counts).elements()))
[2, 3]
[1, 4]
[5]
[2, 2, 3]
[2, 3]
[1, 2, 4]
[3, 5]

前三行輸出展示唯一值的交集和有方向的差集。如果還需要恰好出現在一個集合中的值,請使用 left_set ^ right_set;對這些輸入,它會以未指定順序產生唯一值 1、4 和 5。

使用串列推導式保留結果順序

集合結果不會保留第一個串列的順序。輸出順序重要時,先建立一次成員集合,再掃描需要保留順序的串列。在前面的範例中,right_members 在推導式之前只建立一次,而不是為 left 中的每個元素重建集合或線性掃描第二個串列。

第四行輸出 [2, 2, 3] 保留了 left 的順序和重複出現的元素。這個結果有意是不對稱的:改為掃描 right 就會保留 right 的順序和重複項。若成員值不可雜湊,可對另一個串列使用基於相等性的直接成員檢查,但要知道大串列上的重複掃描可能成本更高。

使用 Counter 保留交集和差集中的次數

集合操作回答的是唯一值問題。Counter 操作回答同類問題,同時保留計數:

  • left_counts & right_counts 為每個共同值保留最小的正計數。
  • left_counts - right_counts 扣除計數後只保留正的餘數。
  • right_counts - left_counts 給出相反方向的差集。
  • .elements() 將結果計數重新展開為單獨的值。

在已驗證的範例中,多重集合交集是 [2, 3],不是 [2, 2, 3]:2 在左側出現兩次、右側只出現一次,所以最小計數為一。左側的有方向餘數是 [1, 2, 4],右側餘數是 [3, 5]。

對於庫存、投票、帶重複的標籤或其他數量有意義的資料,請選擇此方法。普通集合會悄悄抹掉這些資訊。

Counter 算術會從這些多重集合結果中移除零和負計數。這對「剩餘項目」問題很有幫助,但不同於對每個可能鍵進行普通數值減法。若應用必須保留零或負的餘額,請直接檢查計數器。

處理不可雜湊的值並選擇正確方法

set() 和 Counter 都要求元素可雜湊。串列可變且不可雜湊,因此巢狀串列會觸發 TypeError;直接串列相等比較仍可正常工作:

"""Show the unhashable-item boundary of set and Counter comparisons."""

from collections import Counter

left = [[1], [2]]
right = [[1], [2]]

print(left == right)
for name, operation in (("set", set), ("Counter", Counter)):
    try:
        operation(left)
    except TypeError as error:
        print(f"{name}: {error}")
True
set: cannot use 'list' as a set element (unhashable type: 'list')
Counter: unhashable type: 'list'

set 的確切診斷資訊可能隨 Python 版本變化,因此應將例外類型和元素不可雜湊這一原因視為穩定行為。若巢狀序列可以用不可變形式表示,請在使用集合或 Counter 前把每個內部串列轉換為元組;否則,繼續使用符合所需結果的基於相等性的比較。

簡言之,選擇符合資料含義的表示方式:有序序列用 ==,無序多重集合用 Counter,唯一值用 set(),篩選輸出用保留順序的推導式。明確順序和重複規則,才能避免看似正確卻回答了錯誤問題的比較。