0

0

python中怎么对列表去重?

穿越時空

穿越時空

发布时间:2025-09-12 15:14:01

|

1068人浏览过

|

来源于php中文网

原创

最常用且高效的方法是使用set()进行去重,适用于元素可哈希且无需保留顺序的场景;若需保留原始顺序,推荐使用dict.fromkeys()(Python 3.7+),其兼具高效性与顺序保持能力;对于不可哈希元素(如列表、字典),则只能通过遍历并逐项比较的方式实现去重,虽性能较低但通用性强。这三种方法分别对应不同需求:set适合大多数常规去重,dict.fromkeys兼顾效率与顺序,手动循环则应对复杂数据类型。性能方面,前两者平均时间复杂度为O(N),远优于第三种的O(N²)。实际应用中应根据元素类型和顺序要求选择合适方案。

python中怎么对列表去重?

在Python中对列表进行去重,最常用也最直接的方法是利用

set
(集合)数据结构,因为它天然地只存储唯一元素。将列表转换为集合,然后再转换回列表,就能高效地移除重复项。

解决方案

当我们需要从Python列表中移除重复项时,有几种方法可以选择,每种都有其适用场景和考量。我个人在不同情境下会灵活运用它们。

1. 使用

set()
进行去重(最常用且高效)

这是最简洁也通常是最高效的方法,尤其适用于列表元素都是可哈希(hashable)类型(如数字、字符串、元组)的情况。

立即学习Python免费学习笔记(深入)”;

original_list = [1, 2, 2, 3, 4, 4, 5, 1]
unique_list = list(set(original_list))
print(unique_list)
# 输出: [1, 2, 3, 4, 5] (顺序可能与原列表不同)

我的看法:

set
的效率非常高,因为它内部使用了哈希表。对于绝大多数场景,如果对元素的原始顺序没有要求,这绝对是首选。但要记住,它会打乱原始顺序,这在某些数据处理流程中可能会是个坑。

2. 使用

dict.fromkeys()
结合
list()
(保留原始顺序,Python 3.7+)

这个方法利用了字典键的唯一性。

dict.fromkeys()
会创建一个新字典,其键来自提供的序列,值默认为
None
。由于字典会保留键的插入顺序(从Python 3.7开始),我们可以巧妙地利用这一点。

original_list = [1, 2, 2, 3, 4, 4, 5, 1]
unique_list_ordered = list(dict.fromkeys(original_list))
print(unique_list_ordered)
# 输出: [1, 2, 3, 4, 5] (保留了第一次出现的顺序)

我的看法: 这个方法简直是神器!它兼顾了简洁性和效率(内部实现也依赖哈希),同时解决了

set
方法不保留顺序的问题。如果你的元素是可哈希的,并且需要保留原始插入顺序,这几乎是完美的解决方案。

3. 使用循环和新列表(适用于不可哈希元素或对性能不极致要求时)

当列表包含不可哈希的元素(如其他列表、字典或自定义对象,除非你为它们实现了

__hash__
__eq__
方法)时,
set
dict.fromkeys
就无能为力了。这时,我们只能通过遍历原始列表,并将不重复的元素添加到新列表中。

original_list = [1, 2, [3, 4], 2, [3, 4], 5]
unique_list_manual = []
for item in original_list:
    if item not in unique_list_manual:
        unique_list_manual.append(item)
print(unique_list_manual)
# 输出: [1, 2, [3, 4], 5] (保留了原始顺序,且适用于不可哈希元素)

我的看法: 这种方法虽然看起来“笨拙”一些,但在处理复杂数据类型时却是最可靠的。它的缺点是性能可能不如基于哈希的方法,因为

item not in unique_list_manual
操作在最坏情况下需要遍历
unique_list_manual
的所有元素。但对于小到中等规模的列表,或者当其他方法不适用时,它依然是坚实的选择。

为什么列表去重在Python编程中如此重要?

列表去重远不止是代码上的一个小技巧,它在实际的编程工作中扮演着至关重要的角色。从数据完整性到程序性能,再到用户体验,它的影响无处不在。我经常遇到的情况是,如果不对数据进行去重,后续的逻辑可能会变得异常复杂,甚至出现错误。

想象一下,你正在处理一份用户提交的邮件列表,如果其中有重复的地址,你发出的每一封邮件都可能被发送多次,这不仅浪费资源,还可能让用户感到困扰。或者,你在分析日志文件,统计某个事件的发生次数,如果日志中存在重复的事件记录,你的统计结果就会严重偏离真实情况。

去重能帮助我们:

  • 确保数据唯一性与准确性: 这是最直接的好处。无论是数据库记录、API响应还是用户输入,唯一的数据往往是进行正确分析和处理的基础。
  • 优化程序性能: 处理一个较小的、无重复的数据集通常比处理一个庞大且包含冗余的数据集要快得多。减少数据量意味着更少的内存占用和更快的计算速度。
  • 简化后续逻辑: 当你确信列表中的每个元素都是唯一的时,你可以更自信地编写依赖于此假设的代码,从而避免了为处理重复项而设计的额外复杂逻辑。
  • 提升用户体验: 在展示数据给用户时,例如一个选项列表或一个搜索结果,去除重复项能让信息更清晰、更易读,避免混淆。

在我看来,去重是数据清洗(data cleaning)的一个基本环节,就像整理房间一样,把不必要的重复物品清理掉,才能让整个空间更有效率、更整洁。

当处理大型Python列表时,去重有哪些性能考量?

处理大型列表的去重问题,性能就成了不得不考虑的关键因素。不同的去重方法在面对海量数据时,其效率差异会非常显著。我通常会根据列表的规模和元素特性,权衡选择最合适的方案。

Magic AI Avatars
Magic AI Avatars

神奇的AI头像,获得200多个由AI制作的自定义头像。

下载

1.

set()
方法的性能:

  • 平均时间复杂度: O(N),其中N是列表的长度。这是因为集合的添加操作(以及检查元素是否存在)在平均情况下是常数时间复杂度O(1)。
  • 最坏时间复杂度: O(N^2)。在极少数情况下,如果哈希冲突非常严重,或者Python的哈希函数设计不佳,可能会退化到O(N^2)。但在实际应用中,这种情况非常罕见。
  • 内存使用: 会创建一个与原始列表大小相近的临时集合对象。对于非常大的列表,这可能是一个内存消耗点。

2.

dict.fromkeys()
方法的性能:

  • 平均时间复杂度: 同样是O(N),与
    set()
    方法类似,因为它也依赖于哈希表。
  • 内存使用: 也会创建一个临时字典,其内存占用与
    set
    类似。

3. 循环加

in
检查的方法的性能:

  • 时间复杂度: O(N*M),其中N是原始列表的长度,M是已去重列表的当前长度。在最坏情况下(例如,所有元素都是唯一的),M会逐渐增长到N,导致总时间复杂度接近O(N^2)。
  • 内存使用: 除了原始列表,还会创建一个新的列表来存储唯一元素,内存占用与原始列表相似。

总结和建议:

对于大多数情况,基于哈希的

set()
dict.fromkeys()
方法是性能最优的选择。它们的平均时间复杂度是线性的,这意味着处理的数据量越大,它们的优势越明显。

如果列表非常庞大,比如数百万甚至上亿条记录,并且内存是一个严格的限制,你可能需要考虑流式处理或者使用更专业的库(如Pandas),而不是一次性将所有数据加载到内存中去重。但对于Python内置的数据结构而言,哈希方法依然是首选。

为了验证不同方法的性能差异,我有时会使用Python的

timeit
模块进行简单的基准测试。这能帮助我在特定场景下做出数据驱动的决策。

import timeit

# 准备一个包含大量重复项的列表
list_large = [i for i in range(10000)] * 100 # 100万个元素,1万个唯一值

# 测试 set() 方法
time_set = timeit.timeit("list(set(list_large))", globals={'list_large': list_large}, number=10)
print(f"Set method: {time_set:.4f} seconds")

# 测试 dict.fromkeys() 方法
time_dict_fromkeys = timeit.timeit("list(dict.fromkeys(list_large))", globals={'list_large': list_large}, number=10)
print(f"Dict.fromkeys method: {time_dict_fromkeys:.4f} seconds")

# 测试循环加 in 检查的方法 (对于大列表会非常慢,谨慎运行)
# time_loop = timeit.timeit("""
# unique_list_manual = []
# for item in list_large:
#     if item not in unique_list_manual:
#         unique_list_manual.append(item)
# """, globals={'list_large': list_large}, number=1) # 只运行一次,因为太慢了
# print(f"Loop method: {time_loop:.4f} seconds")

通过这样的测试,你会清晰地看到哈希方法的巨大性能优势。

如何处理不可哈希的列表元素,或者在去重时必须保持原始顺序?

在实际开发中,我们遇到的列表元素并非总是简单的数字或字符串。有时,它们可能是列表、字典或其他自定义对象,而这些类型默认是不可哈希的。同时,在某些业务场景下,列表元素的原始顺序又至关重要。这两种情况都需要我们采取更细致的去重策略。

处理不可哈希的元素:

当列表包含不可哈希的元素时,

set()
dict.fromkeys()
方法会直接抛出
TypeError: unhashable type
错误。这时,我们唯一的选择就是回退到基于迭代和比较的去重方法。

# 包含不可哈希列表的列表
list_of_lists = [[1, 2], [3, 4], [1, 2], [5, 6], [3, 4]]

unique_list_of_lists = []
for item in list_of_lists:
    if item not in unique_list_of_lists:
        unique_list_of_lists.append(item)

print(unique_list_of_lists)
# 输出: [[1, 2], [3, 4], [5, 6]]

这里

item not in unique_list_of_lists
的判断是基于元素的
__eq__
方法(即等值比较),而不是哈希值。对于列表,
[1,2] == [1,2]
会返回
True
,所以这种方法能正确识别重复项。

我的思考: 这种方法虽然性能相对较低,但却是处理复杂数据类型的“万能钥匙”。如果你自定义了类,并且希望它们可以去重,你需要确保为这些类正确实现了

__eq__
方法。如果还想使用
set
dict.fromkeys
,那就需要进一步实现
__hash__
方法,但这通常会增加代码的复杂性。

在去重时保持原始顺序:

正如前面提到的,

list(set(my_list))
会打乱原始顺序。如果顺序是业务逻辑的关键部分,那么我们必须选择能够保留顺序的方法。

  1. list(dict.fromkeys(my_list))
    (推荐用于可哈希元素): 这是最优雅且高效的解决方案,前提是你的列表元素都是可哈希的。从Python 3.7开始,字典会保持键的插入顺序,所以这个方法完美地结合了去重和顺序保留。

    original_data = ['apple', 'banana', 'apple', 'orange', 'banana', 'grape']
    ordered_unique_data = list(dict.fromkeys(original_data))
    print(ordered_unique_data)
    # 输出: ['apple', 'banana', 'orange', 'grape']
  2. 循环加

    in
    检查的方法 (适用于不可哈希元素或作为通用方案): 这种方法天生就能保持元素的原始插入顺序,因为它是一个接一个地检查并添加到新列表中。

    mixed_list = [1, 'a', [1,2], 1, 'a', {'key': 'value'}, [1,2]]
    ordered_unique_mixed = []
    for item in mixed_list:
        if item not in ordered_unique_mixed:
            ordered_unique_mixed.append(item)
    print(ordered_unique_mixed)
    # 输出: [1, 'a', [1, 2], {'key': 'value'}]

我的经验之谈: 我不止一次地因为忽略了

set
会打乱顺序的特性而掉入坑里。尤其是在处理一些需要按时间顺序或特定逻辑顺序排列的数据时,这种“顺序丢失”可能会导致非常隐蔽的bug。因此,在选择去重方法时,我总是会先问自己两个问题:1. 元素是否可哈希? 2. 原始顺序是否需要保留?这两个问题的答案,基本就能指导我选择最合适的去重策略了。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

79

2025.12.04

Python 数据清洗与预处理实战
Python 数据清洗与预处理实战

本专题系统讲解 Python 在数据清洗与预处理中的核心技术,包括使用 Pandas 进行缺失值处理、异常值检测、数据格式化、特征工程与数据转换,结合 NumPy 高效处理大规模数据。通过实战案例,帮助学习者掌握 如何处理混乱、不完整数据,为后续数据分析与机器学习模型训练打下坚实基础。

32

2026.01.31

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

338

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

225

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

138

2026.02.12

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

760

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1567

2023.10.24

C# ASP.NET Core微服务架构与API网关实践
C# ASP.NET Core微服务架构与API网关实践

本专题围绕 C# 在现代后端架构中的微服务实践展开,系统讲解基于 ASP.NET Core 构建可扩展服务体系的核心方法。内容涵盖服务拆分策略、RESTful API 设计、服务间通信、API 网关统一入口管理以及服务治理机制。通过真实项目案例,帮助开发者掌握构建高可用微服务系统的关键技术,提高系统的可扩展性与维护效率。

76

2026.03.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号