杰瑞科技汇

Python list如何高效删除重复元素?

在 Python 中,删除列表中的重复元素有多种方法,每种方法都有其适用场景和优缺点,下面我将为你详细介绍几种最常用和最高效的方法。

使用 set(最常用、最简洁)

这是最直接、最 Pythonic 的方法,利用 set(集合)的特性:集合中的元素是唯一的。

原理:

  1. 将列表转换为 set,自动去除重复元素。
  2. 再将 set 转换回列表。

代码示例:

my_list = [1, 2, 5, 2, 'a', 'b', 'a', 5]
# 1. 转换为 set 去重
unique_set = set(my_list)
# unique_set 现在是 {1, 2, 5, 'b', 'a'} (注意:集合是无序的)
# 2. 转换回 list
new_list = list(unique_set)
print(new_list)
# 输出可能是: [1, 2, 5, 'b', 'a'] 或 [1, 2, 5, 'a', 'b'] 等,顺序不确定

优点:

  • 代码简洁:一行代码就能完成。
  • 性能高效:对于大多数情况,这是最快的方法之一,时间复杂度平均为 O(n)。

缺点:

  • 不保留原始顺序set 是无序的,所以转换后的列表元素顺序会与原始列表不同,如果需要保留顺序,请使用下面的方法。

保留原始顺序(推荐)

如果你需要在去重的同时保留元素第一次出现的顺序,可以使用 dict.fromkeys()collections.OrderedDict

方法 2.1:使用 dict.fromkeys() (Python 3.7+ 后保证顺序)

从 Python 3.7 开始,字典(dict)会记住元素的插入顺序,我们可以利用这个特性。

原理:

  1. 使用 dict.fromkeys(my_list) 创建一个字典,列表中的元素作为键,值都为 None
  2. 由于字典的键是唯一的,所以重复的元素会被自动去重。
  3. 因为字典保留了插入顺序,所以键的顺序就是列表中元素首次出现的顺序。
  4. list() 将字典的键转换为列表。

代码示例:

my_list = [1, 2, 5, 2, 'a', 'b', 'a', 5]
# dict.fromkeys() 会创建一个字典,键来自 my_list,值都为 None
# 然后我们只取键,就得到了去重且顺序不变的列表
new_list = list(dict.fromkeys(my_list))
print(new_list)
# 输出: [1, 2, 5, 'a', 'b'] 顺序完美保留

优点:

  • 保留顺序:完美保留了元素首次出现的顺序。
  • 性能高效:时间复杂度为 O(n),比遍历列表检查要快得多。
  • 代码简洁:非常 Pythonic 的写法。

缺点:

  • 依赖 Python 版本:虽然 Python 3.7+ 已将字典顺序作为标准特性,但在更早的版本中(如 3.6 及以前),这种行为是作为实现细节,不保证,对于需要兼容旧版本的环境,请使用方法 2.2。

方法 2.2:使用 collections.OrderedDict (兼容所有版本)

这是在 Python 3.7 之前,为了保留顺序而去重的标准方法。

原理: 与方法 2.1 类似,但明确使用 OrderedDict 来保证顺序。

代码示例:

from collections import OrderedDict
my_list = [1, 2, 5, 2, 'a', 'b', 'a', 5]
# 使用 OrderedDict 来保证顺序
new_list = list(OrderedDict.fromkeys(my_list))
print(new_list)
# 输出: [1, 2, 5, 'a', 'b']

优点:

  • 保留顺序:明确地保证了元素的插入顺序。
  • 兼容性好:适用于所有 Python 版本。

缺点:

  • 需要导入 collections 模块,代码稍显冗长。

使用列表推导式(手动保留顺序)

如果你想手动控制去重逻辑,或者在不使用 set 的情况下实现,可以使用列表推导式结合一个辅助集合。

原理:

  1. 创建一个空集合 seen 用于记录已经出现过的元素。
  2. 遍历原始列表中的每一个元素。
  3. 如果元素不在 seen 集合中,就把它添加到新列表,并放入 seen 集合中。
  4. 如果元素已经在 seen 中,就跳过它。

代码示例:

my_list = [1, 2, 5, 2, 'a', 'b', 'a', 5]
seen = set()
new_list = []
for item in my_list:
    if item not in seen:
        new_list.append(item)
        seen.add(item)
print(new_list)
# 输出: [1, 2, 5, 'a', 'b']

优点:

  • 保留顺序:可以精确控制元素的添加顺序。
  • 逻辑清晰:代码的意图非常明确,易于理解。

缺点:

  • 代码稍长:相比 dict.fromkeys(),需要更多的代码行。
  • 性能略低:虽然时间复杂度也是 O(n),但需要手动循环和判断,通常比 dict.fromkeys() 慢一点点。

使用 for 循环手动删除(不推荐)

这种方法通过创建一个新列表,然后遍历旧列表,只把没出现过的元素添加到新列表中,这与方法三的逻辑类似,只是写法不同。

代码示例:

my_list = [1, 2, 5, 2, 'a', 'b', 'a', 5]
new_list = []
for item in my_list:
    if item not in new_list:
        new_list.append(item)
print(new_list)
# 输出: [1, 2, 5, 'a', 'b']

优点:

  • 逻辑简单:对于初学者来说最容易理解。

缺点:

  • 性能极差if item not in new_list 这句代码,对于列表来说,每次检查的平均时间复杂度是 O(k),k 是 new_list 的长度,总的时间复杂度会变成 O(n²),当列表很大时,这个方法会非常慢。请尽量避免使用这种方法。

总结与如何选择

方法 保留顺序 代码简洁性 性能 适用场景
list(set(my_list)) 极高 当你不关心顺序,只想要一个包含唯一元素的列表时。
list(dict.fromkeys(my_list)) 是 (Python 3.7+) 强烈推荐,当你在保留顺序的同时需要高效去重时,这是现代 Python 的最佳选择。
collections.OrderedDict 是 (所有版本) 当你需要兼容旧版 Python (3.6及以前) 并保留顺序时。
列表推导式 + set 当你需要更精细的逻辑控制,或者不使用 dict 时。
for 循环 + in 列表 极低 (O(n²)) 不推荐,仅用于学习理解,性能瓶颈明显,应避免在生产代码中使用。

最终建议:

  • 如果不需要保留顺序:直接使用 list(set(your_list))
  • 如果需要保留顺序(强烈推荐):使用 list(dict.fromkeys(your_list)),这是目前最平衡、最现代的解决方案。
分享:
扫描分享到社交APP
上一篇
下一篇