在列表中去除重复项

1448

如何检查列表是否有任何重复项,并返回一个没有重复项的新列表?


1
如何使用多进程在一个非常大的列表中删除重复项? - Darkonaut
1
有趣的是,这里的所有顶级答案都没有回答实际问题:创建一个仅包含原始列表中未重复项的新列表。我将其解读为 [1, 2, 3, 4, 5, 2, 4] -> [1, 3, 5],因为2和4是重复的。 - 9769953
根据您的说法,使用Rev 11并仅保留由顶部答案回答的第一个子问题(即[1,2,3,1]→[1,2,3])是否有意义? 接受的答案暗示了可能实现第二个子问题的方法(即[1,2,3,1]→[2,3])。 目前,问题和最佳答案在某种程度上不完全同步。 - Mateen Ulhaq
@MateenUlhaq 我更喜欢保留原始问题。此外,第11版更改了问题以更好地适应答案,但不一定适合原始问题。我想这取决于您希望SO成为多少论坛/邮件列表风格,或者与技巧和技巧网站(具有非常纯净的问题和答案)有多接近。我认为两者都无法实现。 - 9769953
换句话说,这将使问题成为 从另一个列表中删除所有出现的元素 的重复,该问题从一开始就提得更好。但似乎几乎每个人都看到了不同的问题。 - Karl Knechtel
显示剩余2条评论
58个回答

7
更好的方法可能是:
import pandas as pd

myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)

#> [1, 2, 3, 5, 6, 7, 8]

并且顺序保持不变。


2
尽管这样做可能很有效,但是为此目的使用像 pandas 这样的大型库似乎有些过头了。 - Glutexo

7

这个方法会关注顺序而不会太麻烦(使用OrderdDict和其他方式)。可能不是最Pythonic的方式,也不是最简单的方式,但是可以解决问题:

def remove_duplicates(item_list):
    ''' Removes duplicate items from a list '''
    singles_list = []
    for element in item_list:
        if element not in singles_list:
            singles_list.append(element)
    return singles_list

  1. 你永远不应该遮蔽内置名称(至少和 list 一样重要);
  2. 你的方法在 list 中元素数量上呈二次方级别,扩展性极差。
- Eli Korvigo
1
  1. 没错,但这只是个例子。
  2. 正确,这正是我提供它的原因。这里发布的所有解决方案都有优缺点。有些牺牲了简单性或秩序,而我则牺牲了可扩展性。
- cgf

6

保持顺序减少变量:

假设我们有一个列表:

l = [5, 6, 6, 1, 1, 2, 2, 3, 4]

减少变量(效率低下):

>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]

5倍速度更快,但更加精密。

>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]

解释:
default = (list(), set())
# user list to keep order
# use set to make lookup faster

def reducer(result, item):
    if item not in result[1]:
        result[0].append(item)
        result[1].add(item)
    return result

reduce(reducer, l, default)[0]

6
您可以使用以下函数:
def rem_dupes(dup_list): 
    yooneeks = [] 
    for elem in dup_list: 
        if elem not in yooneeks: 
            yooneeks.append(elem) 
    return yooneeks

例子:

my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']

使用方法:

rem_dupes(my_list)

这是一个包含重复元素的列表。


由于它会创建一个副本,因此不适用于大型列表。 - ingyhere
@ingyhere,楼主没有提到任何关于大型列表的建议。每种实现方式都存在权衡取舍,因此默认每个答案都必须是“最具可扩展性”的前提是错误的。 - Cybernetic

6

有很多其他的答案提出了不同的方法来完成这个任务,但是它们都是批量操作,并且其中一些会丢失原始顺序。这可能取决于你的需求而可以接受,但如果你想按照每个值的第一个实例的顺序迭代值,并且你想在运行时逐个删除重复项而不是一次性删除全部重复项,那么你可以使用这个生成器:

def uniqify(iterable):
    seen = set()
    for item in iterable:
        if item not in seen:
            seen.add(item)
            yield item

这将返回一个生成器/迭代器,因此您可以在任何可以使用迭代器的地方使用它。
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
    print(unique_item, end=' ')

print()

输出:

1 2 3 4 5 6 7 8

如果你想要一个列表,你可以这样做:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))

print(unique_list)

输出:

[1, 2, 3, 4, 5, 6, 7, 8]

seen = set(iterable); for item in seen: yield item 几乎肯定更快。(我没有尝试过这个特定的情况,但这就是我的猜测。) - dylnmc
3
@dylnmc,那是一个批量操作,并且也会失去排序。我的回答特别是要即时进行,并按照首次出现的顺序排列。 :) - Cyphase

5
不使用 set:
data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
    if dat not in uni_data:
        uni_data.append(dat)

print(uni_data) 

5

使用 set

a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a

使用唯一的

import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a

5

Python内置类型的神奇之处

在Python中,仅通过Python的内置类型就可以很容易地处理像这样的复杂情况。

让我来向你展示如何做到!

方法1:通用情况

一行代码的方式(1 line code)可以在保持排序顺序的同时删除列表中的重复元素。

line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)

你将获得结果。
[1, 2, 3, 5, 6, 7, 8]

方法2:特殊情况

TypeError: unhashable type: 'list'

处理不可哈希对象的特殊情况 (3行代码)

line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]

tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list

print (new_line)

你将会得到以下结果:
[
  ['16.4966155686595', '-27.59776154691', '52.3786295521147'], 
  ['17.6508629295574', '-27.143305738671', '47.534955022564'], 
  ['18.8051102904552', '-26.688849930432', '42.6912804930134'], 
  ['19.5504702331098', '-26.205884452727', '37.7709192714727'], 
  ['20.2929416861422', '-25.722717575124', '32.8500163147157']
]

由于元组是可哈希的,而且你可以轻松地在列表和元组之间转换数据。

4

在Python 3中,有一种非常简单的方法:

>>> n = [1, 2, 3, 4, 1, 1]
>>> n
[1, 2, 3, 4, 1, 1]
>>> m = sorted(list(set(n)))
>>> m
[1, 2, 3, 4]

2
sorted(list(...)) 是多余的(sorted 已经隐式地将其参数转换为新的 list,对其进行排序,然后返回新的 list,因此同时使用两者意味着制作一个不必要的临时 list)。如果结果不需要排序,请仅使用 list,如果结果需要排序,请仅使用 sorted - ShadowRanger

4

不幸的是,这里大多数答案要么没有保留顺序,要么太长了。这里有一个简单的、保留顺序的答案。

s = [1,2,3,4,5,2,5,6,7,1,3,9,3,5]
x=[]

[x.append(i) for i in s if i not in x]
print(x)

这将会给你一个去除重复项但保持顺序的x。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接