
本文详解如何在 Python 中高效去除列表中连续重复元素,同时严格保持原始顺序和非相邻重复项——适用于数据清洗、ETL 处理及 Snowflake 等场景。
本文详解如何在 python 中高效去除列表中**连续重复元素**,同时严格保持原始顺序和非相邻重复项——适用于数据清洗、etl 处理及 snowflake 等场景。
在数据处理中,常需对有序序列进行“去重”,但关键限制是:仅合并相邻的重复值,而非全局去重。例如 [25, 15, 15, 13, 18, 15] 应变为 [25, 15, 13, 18, 15](第二个 15 与前一个 15 相邻而被压缩,但末尾独立的 15 予以保留)。这种操作称为 consecutive deduplication(相邻去重),是典型的“运行长度压缩(run-length encoding)”简化版。
✅ 推荐方案:itertools.groupby(简洁、高效、Pythonic)
最优雅且性能优异的方式是使用标准库 itertools.groupby —— 它将连续相同元素自动分组,我们只需提取每组的键(即首个元素)即可:
from itertools import groupby
# 示例输入:多行序列数据
data = [
[8, 8, 8, 8, 5, 7],
[8, 5, 5, 5, 7, 8, 7, 7],
[25, 15, 15, 13, 18],
[25, 15, 15, 13, 18, 15]
]
# 一行实现相邻去重
deduped = [[k for k, _ in groupby(sublist)] for sublist in data]
for row in deduped:
print("->".join(map(str, row)))
输出结果:
8->5->7 8->5->7->8->7 25->15->13->18 25->15->13->18->15
? groupby 的核心逻辑:它不预先排序,只按原始顺序将连续相等元素聚为一组。因此 groupby([1,1,2,2,1]) 会生成三组 (1, ...), (2, ...), (1, ...),完美满足需求。
? 手动实现(便于理解逻辑)
若需避免导入、或用于教学/调试,可手动遍历实现:
def dedupe_consecutive(lst):
if not lst:
return []
result = [lst[0]] # 初始化,首元素必保留
for i in range(1, len(lst)):
if lst[i] != lst[i-1]: # 仅当与前一元素不同才追加
result.append(lst[i])
return result
# 应用到全部数据
deduped_manual = [dedupe_consecutive(sub) for sub in data]
该逻辑清晰、空间友好(O(n) 时间,O(1) 额外空间),适合嵌入自定义清洗管道。
⚠ 注意事项与最佳实践
- 不要使用 set() 或 dict.fromkeys():它们会破坏顺序或误删非相邻重复项(如 list(dict.fromkeys([25,15,15,18,15])) → [25,15,18],丢失末尾 15)。
-
Snowflake 用户提示:SQL 层可借助 LAG() 窗口函数实现:
SELECT col_a FROM ( SELECT col_a, LAG(col_a) OVER (ORDER BY seq) AS prev_col_a FROM your_table ) WHERE col_a != prev_col_a OR prev_col_a IS NULL; - 空列表/单元素安全:上述两种方法均天然支持边界情况,无需额外判断。
- 性能对比:groupby 在大数据量下显著快于纯 Python 循环,因其底层 C 实现;手动实现则更易调试和定制(如添加日志、条件过滤)。
掌握相邻去重是构建健壮数据流水线的基础能力。推荐优先使用 itertools.groupby —— 简洁、可靠、符合 Python 哲学。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











