游乐游手机版
首页/业界动态/文章详情

还在乱用列表?集合 set 才是去重和效率神器

时间:2026-04-15 20:02
不是会不会写代码,而是会不会选结构 你有没有遇到过这种情况:为了给列表去重,吭哧吭哧写了好几行循环判断,结果数据量一大,程序就慢得让人心焦。或者,想判断一个元素在不在列表里,程序直接“卡成狗”。 这其实不是代码逻辑的问题,而是数据结构没选对。很多Python初学者都有一个共同的习惯:遇到问题,下意识

不是会不会写代码,而是会不会选结构

你有没有遇到过这种情况:为了给列表去重,吭哧吭哧写了好几行循环判断,结果数据量一大,程序就慢得让人心焦。或者,想判断一个元素在不在列表里,程序直接“卡成狗”。

这其实不是代码逻辑的问题,而是数据结构没选对。很多Python初学者都有一个共同的习惯:遇到问题,下意识就用列表(list)来解决一切。但你可能不知道,在某些特定场景下,集合(set)才是真正的“降维打击”神器。

回想一下,你是不是写过这样的代码?

users = [1001, 1002, 1002, 1003, 1003, 1003]
result = []
for u in users:
    if u not in result:
        result.append(u)

写完可能觉得:“逻辑清晰,能跑就行”。但现实往往很骨感:一旦数据量上来,性能就会暴跌;代码越堆越长,逻辑也越来越绕。

问题的根源在于,你用错了工具。在真实的开发世界里,选对数据结构,性能提升十倍起步是常有的事。

为什么list会越来越慢?

来看一个最常见的操作:在一个列表中查找某个元素是否存在。

nums = list(range(1000000))
999999 in nums

这行代码在底层做了什么?它需要从列表的第一个元素开始,一个一个地问:“是你吗?”,直到找到目标或者问完所有人。这种查找方式,在算法复杂度里被称为 O(n)。简单说,就是数据量(n)越大,查找所花的时间就越长,呈线性增长。

你可以把它想象成在一条长长的队伍里“排队找人”,必须从头到尾一个个看过去。

set 为什么是效率神器?

同样的任务,换成集合(set)试试:

nums = set(range(1000000))
999999 in nums

几乎是瞬间完成。为什么差距这么大?因为集合的底层实现是哈希表(Hash Table)。

这好比什么呢?列表是“排队找人”,而集合是“直接查身份证号”。每个元素进入集合时,都会根据其值计算出一个唯一的“地址”(哈希值)。查找时,直接去这个地址看一眼就知道有没有,根本不需要遍历。

它的时间复杂度是 O(1),意味着查找时间基本不受数据总量影响,这才是真正的“数据结构碾压”。

去重的3种写法(90%的人只会第一种)

明白了原理,再来看去重这个经典问题。其实写法不止一种,但效率天差地别。

❌ 写法1:低效循环版

result = []
for n in nums:
    if n not in result:
        result.append(n)

这是最直观的写法,但效率最低。因为每次`n not in result`都要遍历一次结果列表,整体时间复杂度达到了 O(n²)。数据量稍大,就能明显感觉到卡顿。

✅ 写法2:set去重(最常用)

result = list(set(nums))

这是最经典的用法,利用集合自动去重的特性,一行代码搞定,速度极快。但有一个需要注意的问题:原始顺序会丢失。因为集合本身是无序的。

? 写法3:保序去重(推荐)

result = list(dict.fromkeys(nums))

如果你需要保留元素第一次出现的顺序,推荐这个方法。它的原理很巧妙:从Python 3.7开始,字典(dict)会保持键(key)的插入顺序。同时,字典的键本身就是不重复的。`dict.fromkeys(nums)`会以nums的元素为键创建一个新字典,自动去重并保序,最后再转回列表即可。

真实项目场景

理论说再多,不如看几个实战场景。

场景1:百万级用户ID去重

user_ids = load_data() # 假设这里加载了百万条数据
unique_users = set(user_ids)

用列表循环可能需要几秒甚至更久,而用集合,往往是几毫秒的事。这在处理日志、用户行为数据时非常实用。

场景2:黑名单快速过滤

blacklist = {1002, 1005, 1010}
users = [1001, 1002, 1003]
safe_users = [u for u in users if u not in blacklist]

将黑名单定义为集合,使得`u not in blacklist`这个判断变成了O(1)的瞬时操作,即使黑名单很大,过滤速度也极快。

场景3:寻找共同好友(集合运算)

a = {1, 2, 3} # 用户A的好友集合
b = {2, 3, 4} # 用户B的好友集合
print(a & b) # 输出: {2, 3},即共同好友

集合支持交集(&)、并集(|)、差集(-)等数学运算,在社交、推荐系统等需要比较群体关系的场景下非常方便。

set 的隐藏技巧

除了去重和查找,集合还有一些巧妙的用法:

自动去重并清理空值:

data = [1, 2, None, 2, None]
clean = {x for x in data if x is not None}
# 结果: {1, 2}

结合集合推导式,可以一步完成过滤和去重。

快速提取字符串中的唯一字符:

text = "aaabbbccc"
print(set(text)) # 输出: {'a', 'b', 'c'}

一行代码判断列表是否有重复元素:

def has_duplicate(nums):
    return len(nums) != len(set(nums))
# 如果列表长度和去重后的集合长度不等,说明一定有重复。

set 的三个大坑

当然,集合并非万能,使用时也要避开几个常见的“坑”:

❌ 无序性:集合中的元素没有固定的顺序。

print(set([3, 1, 2])) # 输出可能是 {1, 2, 3},也可能是其他顺序。

❌ 不能存放可变对象:集合的元素必须是“可哈希的”(hashable)。像列表、字典这类可变对象是不可哈希的,不能作为集合元素。

s = {[1, 2]} # 报错!TypeError: unhashable type: 'list'

❌ 非线程安全(进阶注意):在多个线程同时修改同一个集合时,可能会遇到问题。这在高级并发编程中需要留意。

list vs set 认知升级

很多人在学习Python时感到进步缓慢,问题往往不在于不会写`for`循环或`if`判断,而是一直在用“错误的工具”解决问题。

真正的编程高手思维包含两个层面:一是“我该怎么写这段代码”,二是“我应该用什么数据结构来组织我的数据”。后者往往更能决定程序的效率和优雅程度。

记住一个核心原则:凡是涉及成员查找(`in`操作)或去重的场景,优先考虑使用集合(set),而不是列表(list)。

最后给你一个练习

为了巩固理解,可以尝试实现一个函数,输入一个列表,要求返回:

  1. 去重后的结果(保留原始顺序)。
  2. 一个布尔值,指示原列表是否存在重复元素。
  3. 一个列表,包含所有重复出现的元素(每个重复元素只列一次)。

试试看,你会如何设计?

来源:https://www.51cto.com/article/840181.html
上一篇零跑Lafa5 Ultra正式亮相,专属运动套件,将于4月上市 下一篇斯柯达跨界推出概念自行车铃 DuoBell,号称“铃声能穿透降噪耳机”
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
诺基亚TA-1619入网:1400mAh电池双卡双待新机
业界动态 · 2026-07-01

诺基亚TA-1619入网:1400mAh电池双卡双待新机

诺基亚又有新动作了。7月1日消息,一款型号为TA-1619的诺基亚新机已经拿到了电信设备进网许可,不过证件照目前还没公布。 从入网信息来看,这是一款TD-LTE数字移动电话机,支持TD-LTE网络,属于LTE单天线终端设备。双卡双待、VoLTE语音模式都支持,终端款式为直板。核心配置方面,电池额定容

芯佰微CBMRF900系列国产射频芯片突破海外壁垒
业界动态 · 2026-07-01

芯佰微CBMRF900系列国产射频芯片突破海外壁垒

芯佰微电子发布CBMRF9002和CBMRF9009两款射频收发芯片,采用直接变频架构,覆盖10MHz至7250MHz频段,支持最大450MHz带宽及JESD204B高速接口,性能对标国际,满足5G基站与卫星通信等高端需求,突破海外技术壁垒。

月起私人充电桩可卖电 每度净赚5毛
业界动态 · 2026-07-01

月起私人充电桩可卖电 每度净赚5毛

近期有一则重大利好消息,值得新能源车主们特别留意——车网互动价格机制改革已正式落地。自7月1日起,湖北武汉的新能源车主,可在家中的私人充电桩上通过“卖电”轻松赚钱。具体而言,就是借助峰谷电价差,实现低买高卖,每度电净收益约5毛钱。过去,车网互动(V2G)基本只局限于特定的公共充电站,受试点规模限制,

谷歌发布Nano Banana 2 Lite 4秒出图1元4张
业界动态 · 2026-07-01

谷歌发布Nano Banana 2 Lite 4秒出图1元4张

先说几个关键信息:谷歌DeepMind又给图像生成赛道添了新选项。7月1日发布的消息,Nano Banana 2 Lite正式亮相。这个名字听起来像是水果命名系列大爆发,实际上它的技术代号是Gemini 3 1 Flash Lite Image,属于Gemini 3 1家族。最大的卖点就两个:快,便

技嘉专业电竞装备助力2025 CFS世界总决赛
业界动态 · 2026-07-01

技嘉专业电竞装备助力2025 CFS世界总决赛

2025CFS世界总决赛将于12月3日至14日在重庆举行,来自四大赛区的16支战队参赛。技嘉AORUS作为赛事设备合作伙伴,以主板、显示器等专业硬件保障比赛稳定流畅,并通过赛事反哺研发的闭环模式支持电竞发展。