在Python中识别列表中的重复值

57

使用Python,可以获取列表中哪些值是重复的吗?

我有一个项目列表:

    mylist = [20, 30, 25, 20]

我知道去除重复项的最佳方式是使用set(mylist),但是否可以知道哪些值被重复?如您所见,在此列表中,重复项是第一个和最后一个值。 [0, 3]

在Python中是否可能获得此结果或类似的结果?我正在尝试避免制作过于庞大的if elif条件语句。


可能是在Python列表中查找和列出重复项的重复问题。 - Anderson Green
14个回答

81

这些答案的时间复杂度为O(n),比使用mylist.count()要多一点代码,但在mylist变得更长时效率更高。

如果你只想知道重复项,可以使用collections.Counter。

from collections import Counter
mylist = [20, 30, 25, 20]
[k for k,v in Counter(mylist).items() if v>1]
如果您需要知道索引位置,
from collections import defaultdict
D = defaultdict(list)
for i,item in enumerate(mylist):
    D[item].append(i)
D = {k:v for k,v in D.items() if len(v)>1}

2
你可以使用更紧凑的 [i for key in (key for key, count in Counter(mylist).items() if count > 1) for i, x in enumerate(mylist) if x == key] 来实现这个功能 - 虽然它有点复杂,但你可能想要将生成器表达式分开。 - Gareth Latty
2
你可以编写一个函数 def indices(seq, values):,然后返回 (i for value in values for i, x in enumerate(seq) if x == value)。接着调用 indices(mylist, (key for key, count in Counter(mylist).items() if count > 1)) 即可。这样做非常巧妙(当然,最好不要把它塞进注释里)。 - Gareth Latty

20

这是一个能够完成您要求的列表推导式。正如@Codemonkey所说,该列表从索引0开始,因此重复元素的索引为0和3。

>>> [i for i, x in enumerate(mylist) if mylist.count(x) > 1]
[0, 3]

15
那是O(n^2)的时间复杂度……你可以做得更好。 - JBernardo
2
@Levon,它确实搜索整个列表。 - John La Rooy
21
对于那些不理解O(N^2)含义的人:它意味着对于一个包含10个元素的列表,你将执行100步操作,对于1000个元素则需要执行1百万次操作,对于1百万个元素则需要执行1百万亿次操作,等等。二次性能将极快地降低你的性能。 - Martijn Pieters

10
你可以使用列表压缩和集合来减少复杂度。
my_list = [3, 5, 2, 1, 4, 4, 1]
opt = [item for item in set(my_list) if my_list.count(item) > 1]

7
以下列表推导式将产生重复值:
[x for x in mylist if mylist.count(x) >= 2]

1
正如您所看到的,在此列表中,重复项是第一个和最后一个值。[0, 3] 似乎表示所需的输出。 - Junuxx
我也不太确定为什么这里要加括号。这种方法使用起来也比使用"计数器"要低效得多。 - Gareth Latty
1
@Swiss 不是的。集合推导式只需要花括号,这里的方括号完全没有用处。 - Gareth Latty
2
@Swiss 我不是母语为英语的人,我是在美国学习过程中逐渐掌握了 [ -> (方)括号,( -> 小括号,{ -> 大括号的用法 :) - Levon
1
请注意,这个程序性能非常糟糕。list.count() 是一个O(N)的工作(需要比较列表中的所有元素来计算数量),而你正在对N个元素执行循环,导致二次性能,即O(N^2). 因此,对于10个元素的列表将执行100步,对于1000个元素的列表则是100万步,以此类推。 - Martijn Pieters
显示剩余8条评论

5

使用list.index()的最简单方式,不需要任何中间列表:

z = ['a', 'b', 'a', 'c', 'b', 'a', ]
[z[i] for i in range(len(z)) if i == z.index(z[i])]
>>>['a', 'b', 'c']

你还可以列出重复的本身(例如可能再次包含重复的内容):

[z[i] for i in range(len(z)) if not i == z.index(z[i])]
>>>['a', 'b', 'a']

或者它们的索引:
[i for i in range(len(z)) if not i == z.index(z[i])]
>>>[2, 4, 5]

或者将重复项作为它们的索引列表(仅参考其首次出现),那么原始问题的答案是什么!

[(i,z.index(z[i])) for i in range(len(z)) if not i == z.index(z[i])]
>>>[(2, 0), (4, 1), (5, 0)]

或者将此与项目本身一起使用:
[(i,z.index(z[i]),z[i]) for i in range(len(z)) if not i == z.index(z[i])]
>>>[(2, 0, 'a'), (4, 1, 'b'), (5, 0, 'a')]

或任何其他元素和索引的组合....


3
我尝试了下面的代码来查找列表中的重复值:

1)创建一个重复列表的集合

2)通过在重复列表中查找遍历集合。

glist=[1, 2, 3, "one", 5, 6, 1, "one"]
x=set(glist)
dup=[]
for c in x:
    if(glist.count(c)>1):
        dup.append(c)
print(dup)

输出

[1,'one']

现在获取所有重复元素的索引

glist=[1, 2, 3, "one", 5, 6, 1, "one"]
x=set(glist)
dup=[]
for c in x:
    if(glist.count(c)>1):
        indices = [i for i, x in enumerate(glist) if x == c]
        dup.append((c,indices))
print(dup)

输出

[(1, [0, 6]), ('one', [3, 7])]

希望这能帮助到某人


2

这是我能想到的在列表中查找重复项的最简单方法:

my_list = [3, 5, 2, 1, 4, 4, 1]

my_list.sort()
for i in range(0,len(my_list)-1):
               if my_list[i] == my_list[i+1]:
                   print str(my_list[i]) + ' is a duplicate'

4
如果同一项出现超过两次,你将打印出这些项目的多个副本。 - Martijn Pieters

1
以下代码将获取您所需的结果,包括重复项及其索引值。
  for i in set(mylist):
    if mylist.count(i) > 1:
         print(i, mylist.index(i))

0

你应该对列表进行排序:

mylist.sort()

接下来,像这样迭代它:

doubles = []
for i, elem in enumerate(mylist):
    if i != 0:
        if elem == old:
            doubles.append(elem)
            old = None
            continue
    old = elem

1
这并没有获取项目的索引,这似乎是问者想要的。另外,在Python中创建一个空列表并循环遍历项目以添加一些内容是一种反模式,应使用列表推导式。 - Gareth Latty
这也会多次打印出出现超过两次的项目。 - Martijn Pieters

0

看起来你想要重复元素的索引。这里有一些简短的代码,可以在O(n)的时间内找到它们,而且不使用任何包:

dups = {}
[dups.setdefault(v, []).append(i) for i, v in enumerate(mylist)]
dups = {k: v for k, v in dups.items() if len(v) > 1}
# dups now has keys for all the duplicate values
# and a list of matching indices for each

# The second line produces an unused list. 
# It could be replaced with this:
for i, v in enumerate(mylist):
    dups.setdefault(v, []).append(i)

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