如何在列表中找到重复项并创建另一个包含它们的列表?

697

如何在整数列表中找到重复项并创建另一个包含这些重复项的列表?


3
你希望重复出现的内容只保留一次,还是每次看到都要重复? - moooeeeep
我认为这个问题已经得到了更高效的回答。https://dev59.com/wnRB5IYBdhLWcg3wXmRI#642919 intersection是一个集合的内置方法,应该可以完全满足需求。 - Tom Smith
44个回答

1
这是一个快速生成器,它使用字典将每个元素存储为一个键,并使用布尔值来检查是否已经产生了重复项。
对于所有元素都是可哈希类型的列表:
def gen_dupes(array):
    unique = {}
    for value in array:
        if value in unique and unique[value]:
            unique[value] = False
            yield value
        else:
            unique[value] = True

array = [1, 2, 2, 3, 4, 1, 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, 1, 6]

对于可能包含列表的列表:

def gen_dupes(array):
    unique = {}
    for value in array:
        is_list = False
        if type(value) is list:
            value = tuple(value)
            is_list = True

        if value in unique and unique[value]:
            unique[value] = False
            if is_list:
                value = list(value)

            yield value
        else:
            unique[value] = True

array = [1, 2, 2, [1, 2], 3, 4, [1, 2], 5, 2, 6, 6]
print(list(gen_dupes(array)))
# => [2, [1, 2], 6]

1

我注意到大多数解决方案的复杂度为O(n * n),对于大型列表非常慢。因此,我想分享我编写的函数,支持整数或字符串,并且在最佳情况下的复杂度为O(n)。对于一个包含100k个元素的列表,顶部的解决方案需要超过30秒,而我的函数只需要0.12秒就能完成。

def get_duplicates(list1):
    '''Return all duplicates given a list. O(n) complexity for best case scenario.
    input: [1, 1, 1, 2, 3, 4, 4]
    output: [1, 1, 4]
    '''
    dic = {}
    for el in list1:
        try:
            dic[el] += 1
        except:
            dic[el] = 1
    dupes = []
    for key in dic.keys():
        for i in range(dic[key] - 1):
            dupes.append(key)
    return dupes


list1 = [1, 1, 1, 2, 3, 4, 4]
> print(get_duplicates(list1))
[1, 1, 4]

或者获取唯一的重复项:

> print(list(set(get_duplicates(list1))))
[1, 4]

1
为了解决这个问题,我们可以采用多种不同的方法来解决,这两种方法是常见的解决方案,但在实际场景中实施时,我们还必须考虑时间复杂度。
import random
import time

dupl_list = [random.randint(1,1000) for x in range(500)]
print("List with duplicate integers")
print (dupl_list)


#Method 1 
print("******************Method 1 *************")

def Repeat_num(x):
    _size = len(x)
    repeated = []
    for i in range(_size):
        # print(i)
        k = i + 1
        for j in range(k, _size):
            # print(j)
            if x[i] == x[j] and x[i] not in repeated:
                repeated.append(x[i])
    return repeated

start = time.time()
print(Repeat_num(dupl_list))
end = time.time()
print("The time of execution of above program is :",(end-start) * 10**3, "ms")

print("***************Method 2****************")

#method 2 - using count()
def repeast_count(dup_list):
  new = []
  for a in dup_list:
      # print(a)
      # checking the occurrence of elements
      n = dup_list.count(a)
      # if the occurrence is more than
      # one we add it to the output list
      if n > 1:
          if new.count(a) == 0:  # condition to check
              new.append(a)
  return new


start = time.time()
print(repeast_count(dupl_list))
end = time.time()
print("The time of execution of above program is :",(end-start) * 10**3, "ms")

##样例输出::

List with duplicate integers
[5, 45, 28, 81, 32, 98, 8, 83, 47, 95, 41, 49, 4, 1, 85, 26, 38, 82, 54, 11]
******************Method 1 *************
[]
The time of execution of above program is : 1.1069774627685547 ms
***************Method 2****************
[]
The time of execution of above program is : 0.1881122589111328 ms

一般来说,方法1是不错的选择,但在实际实现中,我更倾向于方法2,因为它比方法1所需时间更少。


1
假设我们有这个元素列表:
a = [1, 2, 3, 2, 1, 5, 6, 5, 5, 5]

我们可以仅使用集合来查找唯一元素。
unique = set()
for num in a:
    if num not in unique:
        unique.add(num)
    else:
        unique = unique - set([num])

最后:

>>> unique
{3, 6}

如果您想获取重复内容,可以简单地执行以下操作:
>>> duplicates = set(a) - unique
>>> duplicates
{1, 2, 5}

注意:

  • 集合中的元素查找时间复杂度为O(1)
  • 集合中的元素删除时间复杂度为O(1)

把 else 子句从 unique = unique - set([num]) 改为 unique.remove(num),这样怎么样? - Daniel Hao

1
尝试这个来检查重复项。
>>> def checkDuplicate(List):
    duplicate={}
    for i in List:
            ## checking whether the item is already present in dictionary or not
            ## increasing count if present
            ## initializing count to 1 if not present

        duplicate[i]=duplicate.get(i,0)+1

    return [k for k,v in duplicate.items() if v>1]

>>> checkDuplicate([1,2,3,"s",1,2,3])
[1, 2, 3]

感谢您发布了一个在受限制的Python环境下运行的解决方案(其中set、groupby或其他导入不可用)。 - Georg Pfolz

0

不需要使用Python的任何数据结构,您可以简单地尝试我的以下代码。 这将适用于查找各种输入(如字符串、列表等)的重复项。

# finding duplicates in unsorted an array 
def duplicates(numbers):
    store=[]
    checked=[]
    for i in range(len(numbers)):
        counter =1 
        for j in range(i+1,len(numbers)):
            if numbers[i] not in checked and numbers[j]==numbers[i] :
                counter +=1 
        if counter > 1 :
            store.append(numbers[i])
            checked.append(numbers[i])
    return store

print(duplicates([1,2,2,3,3,3,4,4,5]))  # output:  [2, 3, 4]
print(duplicates("madam"))              # output:  ['m', 'a']

0
some_list = ['a', 'b', 'c', 'b', 'd', 'm', 'n', 'n']
some_dictionary = {}

for element in some_list:
    if element not in some_dictionary:
       some_dictionary[element] = 1
    else:
        some_dictionary[element] += 1

for key, value in some_dictionary.items():
    if value > 1:
       print(key, end = ' ')

# another way
duplicates = []

for x in some_list:
    if some_list.count(x) > 1 and x not in duplicates:
        duplicates.append(x)

print()
print(duplicates)

来源:这里


0

只需检查所有列表项,如果一个项的第一个索引等于该项的最后一个索引,则返回真:

>>> lastindex = lambda arr, el: len(arr) - arr[::-1].index(el) -1
>>> is_duplicate  = lambda arr, el: arr.index(el) != lastindex(arr, el)
>>> duplicates = lambda arr: [*set(x for x in arr if is_duplicate(arr, x))]
>>> 
>>> a=[2,3,5,7,11,13, 2,17,7,7,17,18,3,19,5,2,7,48,48,2,19]
>>> duplicates(a)
[2, 3, 5, 7, 48, 17, 19]
>>> 

0
def removeduplicates(a):
  seen = set()

  for i in a:
    if i not in seen:
      seen.add(i)
  return seen 

print(removeduplicates([1,1,2,2]))

1
你返回了一个集合而不是请求的列表。集合只包含唯一的元素,因此 if 语句并不是真正必要的。你还应该解释一下,与其他解决方案相比,你的解决方案有什么优势。 - clemens

0

我没有看到一个纯粹使用迭代器的解决方案,所以我们来试试吧。

这需要列表被排序,这可能是这里的缺点。

a = [1,2,3,2,1,5,6,5,5,5]
a.sort()
set(map(lambda x: x[0], filter(lambda x: x[0] == x[1], zip(a, a[1:]))))

{1, 2, 5}

你可以使用下面的代码轻松地在你的机器上检查一百万个潜在重复项的速度:

首先生成数据。

import random
from itertools import chain
a = list(chain(*[[n] * random.randint(1, 2) for n in range(1000000)]))

然后运行测试:

set(map(lambda x: x[0], filter(lambda x: x[0] == x[1], zip(a, a[1:]))))

不用说,这个解决方案只适用于已经排序好的列表。


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