当前位置: 首页 > news >正文

Python 列表去重竟有这么多坑,你的写法可能一直不对

写Python这么多年,最容易翻车的地方往往都是些看起来特简单的小功能。比如列表去重,我见过太多人随手一写就埋坑了,今天刚好借个实际脚本聊聊这事儿。

先看最常见的写法:

def dedupe_basic(items):"""最常见的去重——直接丢进set再转回来"""return list(set(items))

这玩意儿在面试题里出现率高达99%,但用过的人都知道第一个大坑:顺序丢了。你传进去的是 [2, 1, 3, 1, 2],出来的可能是 [1, 2, 3]。数据顺序一旦乱了,后面逻辑就全歪了,尤其在处理时间序列、日志、配置文件这些对顺序敏感的场景。

于是有经验的人会换一招,用字典保持插入顺序(Python 3.7+ dict是有序的):

def dedupe_ordered(items):"""利用dict的key唯一性,同时保持插入顺序"""return list(dict.fromkeys(items))

这个写法干净利落,在绝大多数纯值去重场景下表现很好。但它有第二个大坑:碰上不可哈希的元素直接炸。比如你的列表里有个字典或者列表本身,dict.fromkeys 直接甩给你一个 TypeError: unhashable type: 'dict'。你写个爬虫抓了一堆数据,每个元素是个字典,想去个重,用这方法程序就跪了。

不少新手会退化成双重循环的笨办法:

def dedupe_slow(items):"""最笨的去重——徒手遍历判断"""result = []for item in items:if item not in result:result.append(item)return result

功能上似乎没毛病,字典列表也能去重了,顺序也保持了,但这是第三个大坑,藏得更深:时间复杂度O(n²)。列表一大,比如几千个元素,循环里的 item not in result 每次都在做线性扫描,运行时间直接爆炸。你写个数据分析脚本,10万条记录跑几分钟出不来,用户还以为死机了。

那有没有一个写法,既能保持顺序,又能处理不可哈希的元素,还不至于慢成龟?我项目中用到的这个脚本就是个典型例子,应对的就是这种“混合列表去重”场景——经常处理API返回的复杂数据结构,里面元素可能是字符串、数字、元组、字典,甚至层层嵌套的东西。

核心思路是这样的:用一个 seen 集合记录已经见过的元素,但普通集合只能放可哈希的东西,遇到字典这种“刺头”就单独处理。脚本里我这样写的:

def robust_dedupe(items, key=None):"""通用列表去重,保持顺序,兼容不可哈希元素key: 可选的规范化函数,复杂对象可以自定义去重依据"""seen = set()            # 用来记录可哈希的元素或标识seen_unhashable = []    # 兜底:记录不可哈希对象的身份result = []for item in items:# 计算当前元素的“标识”,用于判断是否重复if key:identifier = key(item)else:identifier = item# 尝试将标识加入集合,不可哈希就坠入备选逻辑try:if identifier not in seen:seen.add(identifier)result.append(item)except TypeError:# 不可哈希元素:退化成线性扫描,但因为这类元素通常不多,影响可控if identifier not in seen_unhashable:seen_unhashable.append(identifier)result.append(item)return result

这段代码的亮点在于分而治之。大部分元素还是走集合判断,保持O(1)的平均查找速度。只有碰到 TypeError(也就是不可哈希的元素)才会落进备用的列表扫描。实际场景里不可哈希元素往往只占少数,所以整体性能依然接近线性。key 参数还给了额外灵活性,比如你要根据字典里的某个字段去重,直接传个 lambda x: x['id'] 就行。

我试过一个极端例子:列表里混了字符串、数字、以及几百个重复的字典,用 robust_dedupe 跑下来0.05秒,而那个双重循环的写法用了将近8秒。差距就是这么大。

当然这个脚本也不是万能药。如果你列表里几乎全是不可哈希的东西,那备用扫描又变成了O(n²),这时候就得换个思路了——比如用 repr 序列化后做集合键,但那是另一个话题。

说到底,列表去重这事就像吃饭用筷子——怎么都能夹起来,但姿势不对要么别扭要么洒一地。下次写去重别直接 list(set(...)) 一把梭了,先想清楚你的数据长什么样、对顺序有没有要求、元素能不能哈希,再用对应的写法。我的经验是,能控制输入结构就尽量用 dict.fromkeys,实在复杂了再用分治的 robust_dedupe,保持简单,别过度设计。

这种小脚本平时不起眼,但攒多了就是效率的护城河。你平时去重都会踩什么坑?可以一起聊聊。

http://www.zskr.cn/news/1482104.html

相关文章:

  • 终极Burp Suite汉化指南:3分钟实现中文界面零门槛安全测试
  • 云原生技术07-Ansible vs Terraform:我该用哪个?2026年IaC工具选型指南
  • 091、编队飞行:虚拟结构法
  • 一条慢 SQL 引发的血案,索引优化远比你想象的复杂
  • 手把手教你用Docker+Jenkins搭建前端自动化部署流水线
  • 汽车电子潜在路径分析:从航天技术到工程实践的防漏电设计
  • P1081 [NOIP 2012 提高组] 开车旅行
  • 如何用Python在3分钟内构建企业级抖音批量下载解决方案
  • 成都旧房翻新价格多少?2026年报价明细+避坑指南+公司对比 - 优家闲谈
  • 别再瞎找AI写论文工具!6款全学科神器,一键极速搞定毕业论文 - 麟书学长
  • 020、配置调试与故障诊断:claude config 诊断命令与 10 个常见错误的修复方案
  • Pearcleaner终极指南:免费开源macOS深度清理工具,彻底告别应用残留
  • C51单片机XBYTE宏详解:外部总线访问与内存映射I/O实战
  • 抖音批量下载工具完全指南:5分钟掌握无水印视频下载技巧
  • 嵌入式触摸屏数字键盘实现:图片映射与区域检测方案详解
  • 抖音批量下载终极指南:5分钟免费获取无水印视频素材
  • 2026回本实测解密:68%商家AI直播闲置亏损!
  • 压敏电阻选型与应用指南:从原理到电路保护设计
  • Chrome浏览器密码输入行为捕获工具:专为授权安全测试设计的轻量级扩展
  • 营业执照OCR识别接口接入实践:文档解析、请求校验与工程化落地指南
  • 杭州阿里总部周边5家广式鸡煲店实测排行 - 奔跑123
  • 手把手写你的第一个 Skill:5 分钟搞定
  • Packmol分子动力学模拟初始构型构建完全指南:从入门到精通
  • D类功放原理与实战:从PWM调制到PCB布局全解析
  • 3分钟掌握Whisky:在Mac上运行Windows程序的终极方案
  • 51单片机入门:从环境搭建到点亮LED的嵌入式开发实战指南
  • 千元迷你主机选购指南:英特尔N150芯片解析与三款热门机型横评
  • 终极指南:用Python快速获取同花顺问财数据的完整教程
  • Fillinger智能填充插件:Illustrator设计效率提升18倍的终极指南
  • Kubernetes HPA 自动扩缩容实战:从基础 CPU 指标到自定义指标的全链路调优