
本文介绍如何使用 Python 去除列表中相邻重复元素(即仅合并连续相同的数字),同时严格保持原始顺序和非连续重复项的完整性,适用于数据清洗、ETL 预处理等场景。
本文介绍如何使用 python 去除列表中**相邻重复元素**(即仅合并连续相同的数字),同时严格保持原始顺序和非连续重复项的完整性,适用于数据清洗、etl 预处理等场景。
在实际数据处理中,我们常遇到形如 8->8->8->5->7 的序列,目标是将其压缩为 8->5->7——注意:这并非全局去重(如 set()),而是仅移除连续重复项(consecutive duplicates),保留首次出现位置,并维持所有非相邻重复值(例如 [8,5,5,5,7,8,7,7] → [8,5,7,8,7])。这一操作在日志解析、时序数据降噪、Snowflake 数仓预处理中尤为常见。
✅ 推荐方案:itertools.groupby(简洁、高效、Pythonic)
Python 标准库 itertools.groupby 是专为此类任务设计的工具:它将连续相同元素自动分组,每组返回 (key, group_iterator),我们只需提取每个组的 key 即可:
import itertools
# 示例输入:多行数字序列(每行为一个列表)
sequences = [
[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 itertools.groupby(seq)] for seq in sequences]
for result in deduped:
print("->".join(map(str, result)))
输出:
8->5->7 8->5->7->8->7 25->15->13->18 25->15->13->18->15
⚙️ 手动实现(便于理解逻辑)
若需避免依赖 itertools 或需嵌入自定义逻辑(如跳过 None、忽略大小写等),可采用手动遍历方式:
def dedupe_consecutive(seq):
if not seq:
return []
result = [seq[0]] # 初始化,首元素必保留
for i in range(1, len(seq)):
if seq[i] != seq[i-1]: # 仅当与前一元素不同时追加
result.append(seq[i])
return result
# 应用示例
deduped_manual = [dedupe_consecutive(seq) for seq in sequences]
该方法时间复杂度为 O(n),空间复杂度 O(n),逻辑清晰,易于调试和扩展。
⚠️ 注意事项与最佳实践
- 不要混淆 list(set(...)) 或 dict.fromkeys(...):它们会破坏顺序且全局去重,完全不符合本需求;
- itertools.groupby 要求输入已按需分组:它只对连续相同元素分组,不排序也不重排——这正是我们所需的特性;
- 字符串或自定义对象同样适用:只要支持相等比较(==),即可用于 str、tuple 等类型;
- Snowflake 用户提示:SQL 层可用 LAG() + 窗口函数实现类似逻辑,但 Python 处理更灵活;若必须在 Snowflake 中执行,推荐使用 UDTF(User-Defined Table Function)封装上述逻辑;
- 性能对比:对于百万级序列,itertools.groupby 比纯 Python 循环快约 2–3 倍(C 实现优势),且内存更优。
✅ 总结
连续去重(deduplicating consecutive duplicates)是数据预处理的基础操作。优先使用 itertools.groupby —— 它语义明确、性能优异、代码极简;手动实现则适合教学、调试或需特殊条件判断的场景。无论哪种方式,核心原则始终是:只比较当前元素与前一元素,不跨段、不排序、不丢序。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











