Python列表去重的9種方法終極指南
第一章:Python列表去重保持順序方法概述
在Python開發(fā)中,列表去重是一個常見需求,尤其當需要保留元素原始順序時,簡單的集合轉換(set())無法滿足要求。因此,掌握多種既能去除重復項又能保持原有順序的方法至關重要。
使用字典去重(Python 3.7+)
# 利用dict.fromkeys()自動去重并保持順序 original_list = [1, 2, 2, 3, 4, 3, 5] unique_list = list(dict.fromkeys(original_list)) print(unique_list) # 輸出: [1, 2, 3, 4, 5]
使用集合輔助遍歷
def remove_duplicates(lst):
seen = set()
result = []
for item in lst:
if item not in seen:
seen.add(item)
result.append(item)
return result
data = ['a', 'b', 'a', 'c', 'b']
print(remove_duplicates(data)) # 輸出: ['a', 'b', 'c']
性能與適用場景對比
| 方法 | 時間復雜度 | 保持順序 | Python版本要求 |
|---|---|---|---|
| dict.fromkeys() | O(n) | 是 | 3.7+ |
| 集合輔助遍歷 | O(n) | 是 | 所有版本 |
| set() | O(n) | 否 | 所有版本 |
- 若使用Python 3.7及以上,優(yōu)先選擇
dict.fromkeys() - 需兼容舊版本時,采用集合輔助的顯式循環(huán)
- 避免使用
list(set(lst)),因其不保證順序
第二章:基于循環(huán)與條件判斷的傳統(tǒng)去重
2.1 理論基礎:遍歷與成員檢查機制
在數據結構操作中,遍歷與成員檢查是基礎且頻繁的操作。遍歷用于訪問集合中的每個元素,而成員檢查則判斷特定元素是否存在。
常見遍歷方式
- 順序遍歷:線性訪問每個元素,時間復雜度為 O(n)
- 索引遍歷:適用于數組等支持隨機訪問的結構
- 迭代器遍歷:提供統(tǒng)一接口,解耦算法與數據結構
成員檢查實現對比
| 數據結構 | 查找方式 | 平均時間復雜度 |
|---|---|---|
| 切片(Slice) | 線性掃描 | O(n) |
| 哈希表(Map) | 哈希計算 | O(1) |
func contains(list []int, target int) bool {
for _, item := range list { // 遍歷每個元素
if item == target { // 成員檢查邏輯
return true // 找到則提前返回
}
}
return false // 遍歷結束未找到
}
上述代碼展示了線性查找的基本模式:通過 range 遍歷實現元素訪問,并使用值比較完成成員判定,適用于無序小規(guī)模數據場景。
2.2 實踐演示:使用for循環(huán)配合if判斷
在實際開發(fā)中,for循環(huán)常與if條件判斷結合使用,以實現對數據集合的篩選與處理。
基礎語法結構
for i := 0; i < 10; i++ {
if i%2 == 0 {
fmt.Println(i, "是偶數")
}
}
該代碼遍歷0到9的整數,通過if判斷當前值是否為偶數。其中i%2 == 0用于判斷余數是否為零,成立則執(zhí)行打印。
應用場景示例
- 過濾數組中的負數
- 查找滿足條件的第一個元素
- 分類處理不同狀態(tài)值
2.3 性能分析:時間復雜度與空間開銷
在算法設計中,性能分析是評估效率的核心環(huán)節(jié)。時間復雜度衡量執(zhí)行時間隨輸入規(guī)模增長的趨勢,而空間復雜度反映內存占用情況。
常見復雜度對比
- O(1):常數時間,如數組訪問
- O(log n):對數時間,典型為二分查找
- O(n):線性時間,如遍歷鏈表
- O(n²):平方時間,常見于嵌套循環(huán)
代碼示例:線性查找 vs 二分查找
func linearSearch(arr []int, target int) int {
for i := 0; i < len(arr); i++ { // 循環(huán)n次
if arr[i] == target {
return i
}
}
return -1
}
// 時間復雜度:O(n),空間復雜度:O(1)
該函數逐個比較元素,最壞情況下需遍歷全部n個元素,因此時間復雜度為O(n)。僅使用固定額外變量,空間復雜度為O(1)。
2.4 適用場景:小規(guī)模數據與可讀性優(yōu)先
在處理小規(guī)模數據集時,系統(tǒng)設計更傾向于犧牲部分性能以換取更高的可讀性和維護性。這類場景常見于配置管理、本地緩存或原型開發(fā)中,數據量通常不超過數千條記錄。
代碼可讀性優(yōu)于算法復雜度
type Config struct {
Host string `json:"host"`
Port int `json:"port"`
}
// 直接解析JSON配置文件,邏輯清晰,易于調試
該方式雖不如二進制序列化高效,但顯著提升開發(fā)效率和錯誤排查能力。
典型應用場景
- 本地開發(fā)環(huán)境的模擬數據
- 微服務的靜態(tài)配置文件
- CLI工具的參數定義
這些場景下,開發(fā)者更關注語義明確與快速迭代,而非高并發(fā)處理能力。
2.5 優(yōu)化建議:減少in操作的代價
在高頻查詢場景中,`in` 操作可能導致全表掃描,顯著增加數據庫負載。為降低其代價,應優(yōu)先考慮使用索引字段進行查詢。
避免大集合的in查詢
當 `in` 子句包含大量元素時,不僅解析開銷上升,執(zhí)行計劃可能退化為全掃描。建議將大集合拆分為批量小查詢:
-- 不推薦 SELECT * FROM users WHERE id IN (1,2,...,10000); -- 推薦分批處理 SELECT * FROM users WHERE id BETWEEN 1 AND 1000;
上述方式通過范圍查詢替代超長 `in` 列表,提升執(zhí)行效率并減輕解析壓力。
使用臨時表替代超長in列表
- 將待查ID插入臨時表
- 建立索引加速關聯(lián)查詢
- 通過JOIN代替in操作
例如:
CREATE TEMPORARY TABLE tmp_ids (id INT PRIMARY KEY); INSERT INTO tmp_ids VALUES (1),(2),(3); SELECT u.* FROM users u JOIN tmp_ids t ON u.id = t.id;
該方法適用于動態(tài)集合查詢,執(zhí)行計劃更穩(wěn)定,性能可預測。
第三章:利用字典鍵唯一性的去重策略
3.1 理論基礎:哈希表與鍵的不可重復性
哈希表是一種基于鍵值對(key-value)存儲的數據結構,通過哈希函數將鍵映射到數組的特定位置,實現平均時間復雜度為 O(1) 的高效查找。
鍵的唯一性約束
在哈希表中,每個鍵必須是唯一的。若插入已存在的鍵,通常會覆蓋原有值或拒絕插入,以保證數據一致性。
沖突處理機制
當不同鍵映射到同一索引時發(fā)生哈希沖突。常見解決方案包括鏈地址法和開放尋址法。
- 鏈地址法:每個桶存儲一個鏈表或紅黑樹
- 開放尋址法:探測下一個可用位置
type HashMap struct {
data map[string]interface{}
}
func (m *HashMap) Put(key string, value interface{}) {
if m.data == nil {
m.data = make(map[string]interface{})
}
m.data[key] = value // 相同key會自動覆蓋
}上述 Go 代碼展示了哈希表的簡單實現。map 類型天然支持鍵的唯一性,重復賦值將更新原值,體現了鍵不可重復的核心特性。
3.2 實踐演示:手動構建字典映射關系
基礎映射結構設計
使用 Python 字典結構建立清晰的映射關系,便于后續(xù)維護和擴展:
# 定義性別字段的映射字典
gender_map = {
'M': 'Male',
'F': 'Female',
'0': 'Male',
'1': 'Female'
}
該代碼將多種原始編碼(如'M/F'、'0/1')統(tǒng)一映射為標準化字符串。鍵表示源數據取值,值為目標語義標簽,適用于ETL流程中的數據清洗階段。
批量映射應用示例
結合 pandas 對 DataFrame 批量應用映射規(guī)則:
import pandas as pd df['gender_standard'] = df['gender_raw'].map(gender_map)
利用 .map() 方法高效轉換整列數據,未匹配值將自動置為 NaN,便于后續(xù)排查異常值。
3.3 性能對比:相較于列表查找的提升
在數據檢索場景中,傳統(tǒng)線性列表查找的時間復雜度為 O(n),隨著數據量增長,性能瓶頸顯著。而采用哈希表結構后,平均查找時間復雜度降至 O(1),極大提升了響應效率。
典型查找性能對比
| 數據結構 | 平均查找時間 | 最壞情況 |
|---|---|---|
| 列表(List) | O(n) | O(n) |
| 哈希表(Hash Table) | O(1) | O(n) |
代碼實現示例
// 列表查找
func findInList(arr []int, target int) bool {
for _, v := range arr { // 遍歷每個元素
if v == target {
return true
}
}
return false
}
上述函數通過遍歷實現查找,當目標元素位于末尾或不存在時,需掃描全部 n 個元素。相比之下,哈希表通過散列函數直接定位鍵值存儲位置,避免了逐項比較,從而在大多數情況下實現常數時間查找,尤其適用于高頻查詢和大數據集場景。
第四章:借助集合(set)的高效去重技巧
4.1 理論基礎:集合的唯一性與查詢效率
在數據結構設計中,集合(Set)的核心特性是元素的唯一性,這一屬性通過哈希表或平衡樹實現,顯著提升了去重和成員查詢的效率。
唯一性保障機制
集合在插入元素時自動判斷是否存在重復值。以 Go 語言為例:
set := make(map[string]struct{})
if _, exists := set["key"]; !exists {
set["key"] = struct{}{}
}
上述代碼利用空結構體 struct{}{} 節(jié)省內存,鍵的存在性檢查時間復雜度為 O(1),確保高效去重。
查詢性能對比
不同數據結構的查詢效率如下表所示:
| 數據結構 | 平均查詢時間 | 空間開銷 |
|---|---|---|
| 切片(Slice) | O(n) | 低 |
| 集合(Set) | O(1) | 中 |
該特性使集合廣泛應用于緩存、索引構建等高并發(fā)場景。
4.2 實踐演示:邊遍歷邊維護已見元素
在處理數組或鏈表去重、查找重復元素等場景時,邊遍歷邊維護已見元素是一種高效策略。通過哈希集合記錄已訪問值,可實現線性時間復雜度。
核心思路
使用一個輔助數據結構(如哈希表)在遍歷過程中動態(tài)記錄已出現的元素,從而避免重復處理。
func findDuplicates(nums []int) []int {
seen := make(map[int]bool)
var duplicates []int
for _, num := range nums {
if seen[num] {
duplicates = append(duplicates, num)
} else {
seen[num] = true
}
}
return duplicates
}
上述代碼中,seen 映射用于追蹤已遍歷元素。若當前值已存在,則加入結果集。該方法時間復雜度為 O(n),空間復雜度為 O(n),適用于大規(guī)模數據去重判斷。
4.3 性能優(yōu)勢:O(1)平均查找時間的應用
哈希表憑借其O(1)的平均查找時間,在高性能系統(tǒng)中扮演著關鍵角色。這一特性使其在緩存、數據庫索引和集合去重等場景中表現卓越。
典型應用場景
緩存系統(tǒng)(如Redis)利用哈希結構實現快速鍵值查詢
編譯器符號表使用哈希表存儲變量名與地址映射
集合操作(如去重)依賴哈希集合的唯一性保障
代碼示例:簡易哈希映射實現
type HashMap struct {
data []list.List
size int
}
func (m *HashMap) Put(key string, value interface{}) {
index := hash(key) % m.size
bucket := &m.data[index]
for e := bucket.Front(); e != nil; e = e.Next() {
if e.Value.(Entry).key == key {
e.Value = Entry{key, value}
return
}
}
bucket.PushBack(Entry{key, value})
}
上述Go語言片段展示了一個基礎哈希映射的插入邏輯。通過取模運算定位桶位置,鏈表處理沖突。hash(key)為哈希函數輸出,確保均勻分布,從而維持O(1)的平均訪問效率。
4.4 局限性分析:僅適用于不可變元素類型
在并發(fā)編程中,某些同步機制依賴于元素的不可變性來保證線程安全。若元素類型為可變,則可能導致狀態(tài)不一致。
不可變性的核心作用
不可變對象一旦創(chuàng)建,其狀態(tài)無法更改,天然避免了多線程競爭。例如,在 Go 中定義不可變結構體:
type Point struct {
X, Y int
}
// 實例化后字段不可變,適合并發(fā)讀取
該結構體無 setter 方法,確保共享時不被修改。
可變類型的潛在風險
- 共享可變對象可能導致競態(tài)條件
- 即使使用鎖保護,復雜操作仍易出錯
- 緩存一致性難以維護
適用場景對比
| 類型 | 線程安全 | 適用性 |
|---|---|---|
| 不可變 | 是 | 高 |
| 可變 | 否 | 低 |
第五章:第5種方法揭秘——最高效的有序去重方案
核心思路與數據結構選擇
在處理大規(guī)模有序數據流時,傳統(tǒng)去重方法往往面臨內存占用高或時間復雜度劣化的問題。本方案采用“雙指針 + 增量寫入”策略,在原數組上進行就地操作,避免額外空間開銷。
- 維護一個寫指針(writeIndex),指向下一個不重復元素的存儲位置
- 遍歷數組的讀指針(readIndex)與前一元素比較,跳過重復值
- 僅當當前元素與前一元素不同時,將其寫入 writeIndex 位置并遞增
實戰(zhàn)代碼實現(Go語言)
// orderedDeduplicate 對已排序切片進行高效去重,返回去重后長度
func orderedDeduplicate(nums []int) int {
if len(nums) == 0 {
return 0
}
writeIndex := 1 // 第一個元素無需比較
for readIndex := 1; readIndex < len(nums); readIndex++ {
// 只有當前元素不同于前一個時才保留
if nums[readIndex] != nums[readIndex-1] {
nums[writeIndex] = nums[readIndex]
writeIndex++
}
}
return writeIndex // 新長度
}
性能對比分析
| 方法 | 時間復雜度 | 空間復雜度 | 適用場景 |
|---|---|---|---|
| 哈希表去重 | O(n) | O(n) | 無序數據 |
| 雙指針法 | O(n) | O(1) | 有序數據 |
輸入序列 → 判斷是否為首元素 → 否 → 比較與前一元素是否相同 → 是 → 跳過 ↑ ↓ ←←←←←←←←←←←←←←← 否 ←←←← 寫入當前位置并移動指針 ←←←←
到此這篇關于Python列表去重的9種方法終極指南的文章就介紹到這了,更多相關Python列表去重內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
批標準化層 tf.keras.layers.Batchnormalization()解析
這篇文章主要介紹了批標準化層 tf.keras.layers.Batchnormalization(),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-02-02
對python中使用requests模塊參數編碼的不同處理方法
今天小編就為大家分享一篇對python中使用requests模塊參數編碼的不同處理方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-05-05

