【问题标题】:How do I find the duplicates in a list and create another list with them?如何在列表中找到重复项并使用它们创建另一个列表?
【发布时间】:2021-06-16 05:19:10
【问题描述】:

如何在 Python 列表中找到重复项并创建另一个重复项列表?该列表仅包含整数。

【问题讨论】:

标签: python list duplicates


【解决方案1】:

要删除重复项,请使用set(a)。要打印重复项,例如:

a = [1,2,3,2,1,5,6,5,5,5]

import collections
print([item for item, count in collections.Counter(a).items() if count > 1])

## [1, 2, 5]

请注意,Counter 并不是特别有效 (timings),而且在这里可能有点矫枉过正。 set 会表现得更好。此代码按源顺序计算唯一元素列表:

seen = set()
uniq = []
for x in a:
    if x not in seen:
        uniq.append(x)
        seen.add(x)

或者,更简洁:

seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]    

我不推荐后一种风格,因为not seen.add(x)在做什么并不明显(设置add()方法总是返回None,因此需要not)。

要计算没有库的重复元素列表:

seen = set()
dupes = []

for x in a:
    if x in seen:
        dupes.append(x)
    else:
        seen.add(x)

或者,更简洁:

seen = set()
dupes = [x for x in a if x in seen or seen.add(x)]    

如果列表元素不可散列,则不能使用集合/字典,而必须求助于二​​次时间解决方案(将每个元素与每个元素进行比较)。例如:

a = [[1], [2], [3], [1], [5], [3]]

no_dupes = [x for n, x in enumerate(a) if x not in a[:n]]
print no_dupes # [[1], [2], [3], [5]]

dupes = [x for n, x in enumerate(a) if x in a[:n]]
print dupes # [[1], [3]]

【讨论】:

  • @eric:我猜是O(n),因为它只迭代列表一次并且设置查找是O(1)
  • @Hugo,要查看重复列表,我们只需要创建一个名为 dup 的新列表并添加一条 else 语句。例如:dup = []else: dup.append(x)
  • @oxeimon:你可能明白了,但是你 print 在 python 3 print()987654339@ 中是用括号调用的
  • 将您对 set() 的答案转换为仅获取重复项。 seen = set() 然后dupe = set(x for x in a if x in seen or seen.add(x))
  • 对于 Python 3.x:print ([item for item, count in collections.Counter(a).items() if count > 1])
【解决方案2】:

collections.Counter 是 python 2.7 中的新功能:


Python 2.5.4 (r254:67916, May 31 2010, 15:03:39) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-46)] on linux2
a = [1,2,3,2,1,5,6,5,5,5]
import collections
print [x for x, y in collections.Counter(a).items() if y > 1]
Type "help", "copyright", "credits" or "license" for more information.
  File "", line 1, in 
AttributeError: 'module' object has no attribute 'Counter'
>>> 

在早期版本中,您可以改用传统的 dict:

a = [1,2,3,2,1,5,6,5,5,5]
d = {}
for elem in a:
    if elem in d:
        d[elem] += 1
    else:
        d[elem] = 1

print [x for x, y in d.items() if y > 1]

【讨论】:

    【解决方案3】:

    您不需要计数,只需要该项目之前是否见过。针对这个问题改编that answer

    def list_duplicates(seq):
      seen = set()
      seen_add = seen.add
      # adds all elements it doesn't know yet to seen and all other to seen_twice
      seen_twice = set( x for x in seq if x in seen or seen_add(x) )
      # turn the set into a list (as requested)
      return list( seen_twice )
    
    a = [1,2,3,2,1,5,6,5,5,5]
    list_duplicates(a) # yields [1, 2, 5]
    

    以防万一速度很重要,这里有一些时间安排:

    # file: test.py
    import collections
    
    def thg435(l):
        return [x for x, y in collections.Counter(l).items() if y > 1]
    
    def moooeeeep(l):
        seen = set()
        seen_add = seen.add
        # adds all elements it doesn't know yet to seen and all other to seen_twice
        seen_twice = set( x for x in l if x in seen or seen_add(x) )
        # turn the set into a list (as requested)
        return list( seen_twice )
    
    def RiteshKumar(l):
        return list(set([x for x in l if l.count(x) > 1]))
    
    def JohnLaRooy(L):
        seen = set()
        seen2 = set()
        seen_add = seen.add
        seen2_add = seen2.add
        for item in L:
            if item in seen:
                seen2_add(item)
            else:
                seen_add(item)
        return list(seen2)
    
    l = [1,2,3,2,1,5,6,5,5,5]*100
    

    这是结果:(干得好@JohnLaRooy!)

    $ python -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
    10000 loops, best of 3: 74.6 usec per loop
    $ python -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
    10000 loops, best of 3: 91.3 usec per loop
    $ python -mtimeit -s 'import test' 'test.thg435(test.l)'
    1000 loops, best of 3: 266 usec per loop
    $ python -mtimeit -s 'import test' 'test.RiteshKumar(test.l)'
    100 loops, best of 3: 8.35 msec per loop
    

    有趣的是,除了计时本身,使用 pypy 时排名也会略有变化。最有趣的是,基于计数器的方法从 pypy 的优化中受益匪浅,而我建议的方法缓存方法似乎几乎没有效果。

    $ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
    100000 loops, best of 3: 17.8 usec per loop
    $ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
    10000 loops, best of 3: 23 usec per loop
    $ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
    10000 loops, best of 3: 39.3 usec per loop
    

    显然,这种影响与输入数据的“重复性”有关。我设置了l = [random.randrange(1000000) for i in xrange(10000)] 并得到了这些结果:

    $ pypy -mtimeit -s 'import test' 'test.moooeeeep(test.l)'
    1000 loops, best of 3: 495 usec per loop
    $ pypy -mtimeit -s 'import test' 'test.JohnLaRooy(test.l)'
    1000 loops, best of 3: 499 usec per loop
    $ pypy -mtimeit -s 'import test' 'test.thg435(test.l)'
    1000 loops, best of 3: 1.68 msec per loop
    

    【讨论】:

    • 只是好奇 - 这里 seen_add = seen.add 的目的是什么?
    • @Rob 这样您只需调用您之前查找过的函数。否则,每次需要插入时,您都需要查找(字典查询)成员函数 add
    • 检查了我自己的数据和 Ipython 的 %timeit,您的方法在测试中看起来确实最快,但是:“最慢的运行时间比最快的运行时间长 4.34 倍。这可能意味着正在缓存中间结果”
    • @JohnLaRooy 性能提升不错!有趣的是,当我使用 pypy 来评估结果时,基于计数器的方法显着改进。
    【解决方案4】:
    >>> l = [1,2,3,4,4,5,5,6,1]
    >>> set([x for x in l if l.count(x) > 1])
    set([1, 4, 5])
    

    【讨论】:

    • 你有什么理由使用列表推导而不是生成器推导?
    • 确实,一个简单的解决方案,但复杂性是平方的,因为每个 count() 都会重新解析列表,所以不要用于大型列表。
    • @JohnJ,冒泡排序也很简单并且有效。这并不意味着我们应该使用它!
    • @JohnLaRooy 这确实意味着我们不应该使用它,因为几乎总是有一种更有效(和更简单)的方式来进行排序。
    • @watsonic:在一般情况下,您的“简单开关”未能将时间复杂度从平方降低到平方。将 l 替换为 set(l) 只会降低最坏情况的时间复杂度,因此 没有 解决此答案的大规模效率问题。毕竟可能没那么简单。简而言之,不要这样做。
    【解决方案5】:
    list2 = [1, 2, 3, 4, 1, 2, 3]
    lset = set()
    [(lset.add(item), list2.append(item))
     for item in list2 if item not in lset]
    print list(lset)
    

    【讨论】:

      【解决方案6】:

      有点晚了,但可能对某些人有帮助。 对于较大的列表,我发现这对我有用。

      l=[1,2,3,5,4,1,3,1]
      s=set(l)
      d=[]
      for x in l:
          if x in s:
              s.remove(x)
          else:
              d.append(x)
      d
      [1,3,1]
      

      仅显示所有重复项并保留顺序。

      【讨论】:

        【解决方案7】:

        一线解决方案:

        set([i for i in list if sum([1 for a in list if a == i]) > 1])
        

        【讨论】:

          【解决方案8】:

          我在查看相关内容时遇到了这个问题 - 并且想知道为什么没有人提供基于生成器的解决方案?解决这个问题的方法是:

          >>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
          [1, 2, 5]
          

          我担心可扩展性,因此测试了几种方法,包括在小列表上运行良好的幼稚项目,但随着列表变大而可怕地扩展(注意 - 使用 timeit 会更好,但这只是说明性的)。

          我包含了@moooeeeeep 进行比较(它的速度非常快:如果输入列表是完全随机的,则速度最快)和一个 itertools 方法,对于大多数排序的列表来说它再次更快......现在包括来自@firelynx 的 pandas 方法——慢,但并不可怕,而且简单。注意 - 在我的机器上,排序/tee/zip 方法始终是最快的,对于大部分排序的大型列表,moooeeeep 对于随机列表最快,但您的里程可能会有所不同。

          优势

          • 使用相同的代码快速简单地测试“任何”重复项

          假设

          • 重复项只能报告一次
          • 不需要保留重复的订单
          • 重复项可能在列表中的任何位置

          最快的解决方案,1m 条目:

          def getDupes(c):
                  '''sort/tee/izip'''
                  a, b = itertools.tee(sorted(c))
                  next(b, None)
                  r = None
                  for k, g in itertools.izip(a, b):
                      if k != g: continue
                      if k != r:
                          yield k
                          r = k
          

          测试方法

          import itertools
          import time
          import random
          
          def getDupes_1(c):
              '''naive'''
              for i in xrange(0, len(c)):
                  if c[i] in c[:i]:
                      yield c[i]
          
          def getDupes_2(c):
              '''set len change'''
              s = set()
              for i in c:
                  l = len(s)
                  s.add(i)
                  if len(s) == l:
                      yield i
          
          def getDupes_3(c):
              '''in dict'''
              d = {}
              for i in c:
                  if i in d:
                      if d[i]:
                          yield i
                          d[i] = False
                  else:
                      d[i] = True
          
          def getDupes_4(c):
              '''in set'''
              s,r = set(),set()
              for i in c:
                  if i not in s:
                      s.add(i)
                  elif i not in r:
                      r.add(i)
                      yield i
          
          def getDupes_5(c):
              '''sort/adjacent'''
              c = sorted(c)
              r = None
              for i in xrange(1, len(c)):
                  if c[i] == c[i - 1]:
                      if c[i] != r:
                          yield c[i]
                          r = c[i]
          
          def getDupes_6(c):
              '''sort/groupby'''
              def multiple(x):
                  try:
                      x.next()
                      x.next()
                      return True
                  except:
                      return False
              for k, g in itertools.ifilter(lambda x: multiple(x[1]), itertools.groupby(sorted(c))):
                  yield k
          
          def getDupes_7(c):
              '''sort/zip'''
              c = sorted(c)
              r = None
              for k, g in zip(c[:-1],c[1:]):
                  if k == g:
                      if k != r:
                          yield k
                          r = k
          
          def getDupes_8(c):
              '''sort/izip'''
              c = sorted(c)
              r = None
              for k, g in itertools.izip(c[:-1],c[1:]):
                  if k == g:
                      if k != r:
                          yield k
                          r = k
          
          def getDupes_9(c):
              '''sort/tee/izip'''
              a, b = itertools.tee(sorted(c))
              next(b, None)
              r = None
              for k, g in itertools.izip(a, b):
                  if k != g: continue
                  if k != r:
                      yield k
                      r = k
          
          def getDupes_a(l):
              '''moooeeeep'''
              seen = set()
              seen_add = seen.add
              # adds all elements it doesn't know yet to seen and all other to seen_twice
              for x in l:
                  if x in seen or seen_add(x):
                      yield x
          
          def getDupes_b(x):
              '''iter*/sorted'''
              x = sorted(x)
              def _matches():
                  for k,g in itertools.izip(x[:-1],x[1:]):
                      if k == g:
                          yield k
              for k, n in itertools.groupby(_matches()):
                  yield k
          
          def getDupes_c(a):
              '''pandas'''
              import pandas as pd
              vc = pd.Series(a).value_counts()
              i = vc[vc > 1].index
              for _ in i:
                  yield _
          
          def hasDupes(fn,c):
              try:
                  if fn(c).next(): return True    # Found a dupe
              except StopIteration:
                  pass
              return False
          
          def getDupes(fn,c):
              return list(fn(c))
          
          STABLE = True
          if STABLE:
              print 'Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array'
          else:
              print 'Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array'
          for location in (50,250000,500000,750000,999999):
              for test in (getDupes_2, getDupes_3, getDupes_4, getDupes_5, getDupes_6,
                           getDupes_8, getDupes_9, getDupes_a, getDupes_b, getDupes_c):
                  print 'Test %-15s:%10d - '%(test.__doc__ or test.__name__,location),
                  deltas = []
                  for FIRST in (True,False):
                      for i in xrange(0, 5):
                          c = range(0,1000000)
                          if STABLE:
                              c[0] = location
                          else:
                              c.append(location)
                              random.shuffle(c)
                          start = time.time()
                          if FIRST:
                              print '.' if location == test(c).next() else '!',
                          else:
                              print '.' if [location] == list(test(c)) else '!',
                          deltas.append(time.time()-start)
                      print ' -- %0.3f  '%(sum(deltas)/len(deltas)),
                  print
              print
          

          'all dupes' 测试的结果是一致的,在此数组中找到“第一个”重复项,然后是“所有”重复项:

          Finding FIRST then ALL duplicates, single dupe of "nth" placed element in 1m element array
          Test set len change :    500000 -  . . . . .  -- 0.264   . . . . .  -- 0.402  
          Test in dict        :    500000 -  . . . . .  -- 0.163   . . . . .  -- 0.250  
          Test in set         :    500000 -  . . . . .  -- 0.163   . . . . .  -- 0.249  
          Test sort/adjacent  :    500000 -  . . . . .  -- 0.159   . . . . .  -- 0.229  
          Test sort/groupby   :    500000 -  . . . . .  -- 0.860   . . . . .  -- 1.286  
          Test sort/izip      :    500000 -  . . . . .  -- 0.165   . . . . .  -- 0.229  
          Test sort/tee/izip  :    500000 -  . . . . .  -- 0.145   . . . . .  -- 0.206  *
          Test moooeeeep      :    500000 -  . . . . .  -- 0.149   . . . . .  -- 0.232  
          Test iter*/sorted   :    500000 -  . . . . .  -- 0.160   . . . . .  -- 0.221  
          Test pandas         :    500000 -  . . . . .  -- 0.493   . . . . .  -- 0.499  
          

          当列表首先被洗牌时,排序的代价就变得明显了——效率明显下降,@moooeeeeep 方法占主导地位,set 和 dict 方法相似但表现不佳:

          Finding FIRST then ALL duplicates, single dupe of "n" included in randomised 1m element array
          Test set len change :    500000 -  . . . . .  -- 0.321   . . . . .  -- 0.473  
          Test in dict        :    500000 -  . . . . .  -- 0.285   . . . . .  -- 0.360  
          Test in set         :    500000 -  . . . . .  -- 0.309   . . . . .  -- 0.365  
          Test sort/adjacent  :    500000 -  . . . . .  -- 0.756   . . . . .  -- 0.823  
          Test sort/groupby   :    500000 -  . . . . .  -- 1.459   . . . . .  -- 1.896  
          Test sort/izip      :    500000 -  . . . . .  -- 0.786   . . . . .  -- 0.845  
          Test sort/tee/izip  :    500000 -  . . . . .  -- 0.743   . . . . .  -- 0.804  
          Test moooeeeep      :    500000 -  . . . . .  -- 0.234   . . . . .  -- 0.311  *
          Test iter*/sorted   :    500000 -  . . . . .  -- 0.776   . . . . .  -- 0.840  
          Test pandas         :    500000 -  . . . . .  -- 0.539   . . . . .  -- 0.540  
          

          【讨论】:

          • @moooeeeep - 有兴趣了解您对 ifilter/izip/tee 方法的看法。
          • 这个答案非常好。我不明白它没有更多的解释和测试对需要它的人非常有用。
          • 当只有一项乱序时,python 的排序是 O(n)。你应该random.shuffle(c) 来说明这一点。此外,在运行未更改的脚本时,我也无法复制您的结果(完全不同的顺序),所以它可能也取决于 CPU。
          • 谢谢@John-La-Rooy,对 CPU/本地机器的敏锐观察会产生影响 - 所以我应该修改项目 YYMV。使用 O(n) 排序是经过深思熟虑的:重复的元素被插入到不同的位置,专门用于查看该方法的影响,如果在好的(列表的开头)或坏的(列表末尾)使用这些方法的位置。我考虑了一个随机列表 - 例如 random.shuffle - 但我决定只有在我进行更多运行时才有意义!我将不得不返回并基准测试多次运行/随机播放等效项,看看有什么影响。
          • itertools.tee 增加了不必要的开销。尝试c = sorted(c),然后改为a, b = iter(c), iter(c)
          【解决方案9】:

          我会用熊猫做这个,因为我经常使用熊猫

          import pandas as pd
          a = [1,2,3,3,3,4,5,6,6,7]
          vc = pd.Series(a).value_counts()
          vc[vc > 1].index.tolist()
          

          给予

          [3,6]
          

          可能效率不高,但它肯定比许多其他答案的代码少,所以我想我会贡献的

          【讨论】:

          • 还要注意,pandas 包含一个内置的重复功能 pda = pd.Series(a) print list(pda[pda.duplicated()])
          【解决方案10】:

          这是我必须这样做的方式,因为我挑战自己不要使用其他方法:

          def dupList(oldlist):
              if type(oldlist)==type((2,2)):
                  oldlist=[x for x in oldlist]
              newList=[]
              newList=newList+oldlist
              oldlist=oldlist
              forbidden=[]
              checkPoint=0
              for i in range(len(oldlist)):
                  #print 'start i', i
                  if i in forbidden:
                      continue
                  else:
                      for j in range(len(oldlist)):
                          #print 'start j', j
                          if j in forbidden:
                              continue
                          else:
                              #print 'after Else'
                              if i!=j: 
                                  #print 'i,j', i,j
                                  #print oldlist
                                  #print newList
                                  if oldlist[j]==oldlist[i]:
                                      #print 'oldlist[i],oldlist[j]', oldlist[i],oldlist[j]
                                      forbidden.append(j)
                                      #print 'forbidden', forbidden
                                      del newList[j-checkPoint]
                                      #print newList
                                      checkPoint=checkPoint+1
              return newList
          

          所以您的示例如下:

          >>>a = [1,2,3,3,3,4,5,6,6,7]
          >>>dupList(a)
          [1, 2, 3, 4, 5, 6, 7]
          

          【讨论】:

          • 这不是 OP 想要的。他想要一份重复的列表,而不是删除重复的列表。要列出删除重复项的列表,我建议duplist = list(set(a))
          【解决方案11】:

          使用sort() 函数。可以通过循环并检查l1[i] == l1[i+1]来识别重复项。

          【讨论】:

            【解决方案12】:

            接受答案的第三个示例给出了错误的答案,并且不尝试给出重复的答案。这是正确的版本:

            number_lst = [1, 1, 2, 3, 5, ...]
            
            seen_set = set()
            duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
            unique_set = seen_set - duplicate_set
            

            【讨论】:

              【解决方案13】:

              这里有很多答案,但我认为这是一种相对可读且易于理解的方法:

              def get_duplicates(sorted_list):
                  duplicates = []
                  last = sorted_list[0]
                  for x in sorted_list[1:]:
                      if x == last:
                          duplicates.append(x)
                      last = x
                  return set(duplicates)
              

              注意事项:

              • 如果您希望保留重复计数,请去掉演员表 在底部“设置”以获取完整列表
              • 如果您更喜欢使用生成器,请将 duplicates.append(x) 替换为 yield x 和底部的 return 语句(您可以稍后再设置)

              【讨论】:

                【解决方案14】:

                这是一个快速生成器,它使用 dict 将每个元素存储为带有布尔值的键,用于检查重复项是否已经产生。

                对于所有元素都是可散列类型的列表:

                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]
                

                【讨论】:

                  【解决方案15】:

                  在 Python 中通过一次迭代找到受骗者的非常简单快捷的方法是:

                  testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']
                  
                  testListDict = {}
                  
                  for item in testList:
                    try:
                      testListDict[item] += 1
                    except:
                      testListDict[item] = 1
                  
                  print testListDict
                  

                  输出如下:

                  >>> print testListDict
                  {'blue': 3, 'green': 1, 'red': 2}
                  

                  这个以及更多在我的博客http://www.howtoprogramwithpython.com

                  【讨论】:

                  • 这是桶排序的一种变体。
                  【解决方案16】:

                  这是一个简洁明了的解决方案 -

                  for x in set(li):
                      li.remove(x)
                  
                  li = list(set(li))
                  

                  【讨论】:

                  • 但原始列表已丢失。这可以通过将内容复制到另一个列表来解决 - temp = li[:]
                  • 在大型列表上这是一个非常讨厌的练习 - 从列表中删除元素非常昂贵!
                  【解决方案17】:

                  使用熊猫:

                  >>> import pandas as pd
                  >>> a = [1, 2, 1, 3, 3, 3, 0]
                  >>> pd.Series(a)[pd.Series(a).duplicated()].values
                  array([1, 3, 3])
                  

                  【讨论】:

                    【解决方案18】:

                    你可以使用iteration_utilities.duplicates:

                    >>> from iteration_utilities import duplicates
                    
                    >>> list(duplicates([1,1,2,1,2,3,4,2]))
                    [1, 1, 2, 2]
                    

                    或者,如果您只想要每个副本中的一个,则可以将其与 iteration_utilities.unique_everseen 结合使用:

                    >>> from iteration_utilities import unique_everseen
                    
                    >>> list(unique_everseen(duplicates([1,1,2,1,2,3,4,2])))
                    [1, 2]
                    

                    它还可以处理不可散列的元素(但是以性能为代价):

                    >>> list(duplicates([[1], [2], [1], [3], [1]]))
                    [[1], [1]]
                    
                    >>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
                    [[1]]
                    

                    这是这里只有少数其他方法可以处理的问题。

                    基准测试

                    我做了一个快速基准测试,其中包含这里提到的大部分(但不是全部)方法。

                    第一个基准测试仅包含一小部分列表长度,因为某些方法具有O(n**2) 行为。

                    在图表中,y 轴代表时间,因此值越低越好。它还绘制了对数对数,因此可以更好地可视化广泛的值:

                    删除 O(n**2) 方法我做了另一个基准测试,列表中的元素多达 50 万:

                    如您所见,iteration_utilities.duplicates 方法比任何其他方法都快,甚至链接 unique_everseen(duplicates(...)) 也比其他方法更快或同样快。

                    这里要注意的另外一个有趣的事情是,pandas 方法对于小列表非常慢,但可以轻松竞争更长的列表。

                    但是,由于这些基准测试显示大多数方法的性能大致相同,因此使用哪一种方法并不重要(除了具有 O(n**2) 运行时的 3 种方法)。

                    from iteration_utilities import duplicates, unique_everseen
                    from collections import Counter
                    import pandas as pd
                    import itertools
                    
                    def georg_counter(it):
                        return [item for item, count in Counter(it).items() if count > 1]
                    
                    def georg_set(it):
                        seen = set()
                        uniq = []
                        for x in it:
                            if x not in seen:
                                uniq.append(x)
                                seen.add(x)
                    
                    def georg_set2(it):
                        seen = set()
                        return [x for x in it if x not in seen and not seen.add(x)]   
                    
                    def georg_set3(it):
                        seen = {}
                        dupes = []
                    
                        for x in it:
                            if x not in seen:
                                seen[x] = 1
                            else:
                                if seen[x] == 1:
                                    dupes.append(x)
                                seen[x] += 1
                    
                    def RiteshKumar_count(l):
                        return set([x for x in l if l.count(x) > 1])
                    
                    def moooeeeep(seq):
                        seen = set()
                        seen_add = seen.add
                        # adds all elements it doesn't know yet to seen and all other to seen_twice
                        seen_twice = set( x for x in seq if x in seen or seen_add(x) )
                        # turn the set into a list (as requested)
                        return list( seen_twice )
                    
                    def F1Rumors_implementation(c):
                        a, b = itertools.tee(sorted(c))
                        next(b, None)
                        r = None
                        for k, g in zip(a, b):
                            if k != g: continue
                            if k != r:
                                yield k
                                r = k
                    
                    def F1Rumors(c):
                        return list(F1Rumors_implementation(c))
                    
                    def Edward(a):
                        d = {}
                        for elem in a:
                            if elem in d:
                                d[elem] += 1
                            else:
                                d[elem] = 1
                        return [x for x, y in d.items() if y > 1]
                    
                    def wordsmith(a):
                        return pd.Series(a)[pd.Series(a).duplicated()].values
                    
                    def NikhilPrabhu(li):
                        li = li.copy()
                        for x in set(li):
                            li.remove(x)
                    
                        return list(set(li))
                    
                    def firelynx(a):
                        vc = pd.Series(a).value_counts()
                        return vc[vc > 1].index.tolist()
                    
                    def HenryDev(myList):
                        newList = set()
                    
                        for i in myList:
                            if myList.count(i) >= 2:
                                newList.add(i)
                    
                        return list(newList)
                    
                    def yota(number_lst):
                        seen_set = set()
                        duplicate_set = set(x for x in number_lst if x in seen_set or seen_set.add(x))
                        return seen_set - duplicate_set
                    
                    def IgorVishnevskiy(l):
                        s=set(l)
                        d=[]
                        for x in l:
                            if x in s:
                                s.remove(x)
                            else:
                                d.append(x)
                        return d
                    
                    def it_duplicates(l):
                        return list(duplicates(l))
                    
                    def it_unique_duplicates(l):
                        return list(unique_everseen(duplicates(l)))
                    

                    基准 1

                    from simple_benchmark import benchmark
                    import random
                    
                    funcs = [
                        georg_counter, georg_set, georg_set2, georg_set3, RiteshKumar_count, moooeeeep, 
                        F1Rumors, Edward, wordsmith, NikhilPrabhu, firelynx,
                        HenryDev, yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
                    ]
                    
                    args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 12)}
                    
                    b = benchmark(funcs, args, 'list size')
                    
                    b.plot()
                    

                    基准 2

                    funcs = [
                        georg_counter, georg_set, georg_set2, georg_set3, moooeeeep, 
                        F1Rumors, Edward, wordsmith, firelynx,
                        yota, IgorVishnevskiy, it_duplicates, it_unique_duplicates
                    ]
                    
                    args = {2**i: [random.randint(0, 2**(i-1)) for _ in range(2**i)] for i in range(2, 20)}
                    
                    b = benchmark(funcs, args, 'list size')
                    b.plot()
                    

                    免责声明

                    1 这是来自我写过的第三方库:iteration_utilities

                    【讨论】:

                    • 我将在这里伸出我的脖子,并建议编写一个定制库来用 C 而不是 Python 来完成这项工作,这可能不是正在寻找的答案的精神 - 但这是一个合法的做法!我喜欢答案的宽度和结果的图形显示——很高兴看到它们正在收敛,这让我想知道它们是否会随着输入的进一步增加而交叉!问题:与完全随机的列表相比,大多数排序列表的结果是什么?
                    • 感谢基准测试,我现在在my answer 中使用了它。对这种拥挤的情节图像的建议:使用更高的分辨率(我用plt.savefig('duplicates.png', dpi=300) 保存了我的)并删除了实际情节周围的大部分空白。然后图像更大更清晰,无论是在嵌入视图中还是在独立视图中(单击图像时)。较高的分辨率会增加文件大小,但您可以通过降低颜色深度来解决此问题。
                    【解决方案19】:

                    如何简单地通过检查出现次数来遍历列表中的每个元素,然后将它们添加到一个集合中,然后打印重复项。希望这对那里的人有所帮助。

                    myList  = [2 ,4 , 6, 8, 4, 6, 12];
                    newList = set()
                    
                    for i in myList:
                        if myList.count(i) >= 2:
                            newList.add(i)
                    
                    print(list(newList))
                    ## [4 , 6]
                    

                    【讨论】:

                      【解决方案20】:

                      我们可以使用itertools.groupby 来查找所有有重复的项目:

                      from itertools import groupby
                      
                      myList  = [2, 4, 6, 8, 4, 6, 12]
                      # when the list is sorted, groupby groups by consecutive elements which are similar
                      for x, y in groupby(sorted(myList)):
                          #  list(y) returns all the occurences of item x
                          if len(list(y)) > 1:
                              print x  
                      

                      输出将是:

                      4
                      6
                      

                      【讨论】:

                      • 或更简洁:dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
                      【解决方案21】:
                      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]))
                      

                      【讨论】:

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

                      如果不转换为列表,可能最简单的方法如下所示。 这可能在面试时要求不要使用集合时很有用

                      a=[1,2,3,3,3]
                      dup=[]
                      for each in a:
                        if each not in dup:
                          dup.append(each)
                      print(dup)
                      

                      ======= else 获得 2 个单独的唯一值和重复值列表

                      a=[1,2,3,3,3]
                      uniques=[]
                      dups=[]
                      
                      for each in a:
                        if each not in uniques:
                          uniques.append(each)
                        else:
                          dups.append(each)
                      print("Unique values are below:")
                      print(uniques)
                      print("Duplicate values are below:")
                      print(dups)
                      

                      【讨论】:

                      • 这不会导致 a (或原始列表)的重复列表,但这会导致 a (或原始列表)的所有唯一元素的列表。完成“dup”列表后,某人会做什么?
                      【解决方案23】:

                      其他一些测试。当然可以……

                      set([x for x in l if l.count(x) > 1])
                      

                      ...太贵了。使用下一个 final 方法大约快 500 倍(数组越长,结果越好):

                      def dups_count_dict(l):
                          d = {}
                      
                          for item in l:
                              if item not in d:
                                  d[item] = 0
                      
                              d[item] += 1
                      
                          result_d = {key: val for key, val in d.iteritems() if val > 1}
                      
                          return result_d.keys()
                      

                      只有 2 个循环,没有非常昂贵的 l.count() 操作。

                      这是一个比较方法的代码。代码如下,输出如下:

                      dups_count: 13.368s # this is a function which uses l.count()
                      dups_count_dict: 0.014s # this is a final best function (of the 3 functions)
                      dups_count_counter: 0.024s # collections.Counter
                      

                      测试代码:

                      import numpy as np
                      from time import time
                      from collections import Counter
                      
                      class TimerCounter(object):
                          def __init__(self):
                              self._time_sum = 0
                      
                          def start(self):
                              self.time = time()
                      
                          def stop(self):
                              self._time_sum += time() - self.time
                      
                          def get_time_sum(self):
                              return self._time_sum
                      
                      
                      def dups_count(l):
                          return set([x for x in l if l.count(x) > 1])
                      
                      
                      def dups_count_dict(l):
                          d = {}
                      
                          for item in l:
                              if item not in d:
                                  d[item] = 0
                      
                              d[item] += 1
                      
                          result_d = {key: val for key, val in d.iteritems() if val > 1}
                      
                          return result_d.keys()
                      
                      
                      def dups_counter(l):
                          counter = Counter(l)    
                      
                          result_d = {key: val for key, val in counter.iteritems() if val > 1}
                      
                          return result_d.keys()
                      
                      
                      
                      def gen_array():
                          np.random.seed(17)
                          return list(np.random.randint(0, 5000, 10000))
                      
                      
                      def assert_equal_results(*results):
                          primary_result = results[0]
                          other_results = results[1:]
                      
                          for other_result in other_results:
                              assert set(primary_result) == set(other_result) and len(primary_result) == len(other_result)
                      
                      
                      if __name__ == '__main__':
                          dups_count_time = TimerCounter()
                          dups_count_dict_time = TimerCounter()
                          dups_count_counter = TimerCounter()
                      
                          l = gen_array()
                      
                          for i in range(3):
                              dups_count_time.start()
                              result1 = dups_count(l)
                              dups_count_time.stop()
                      
                              dups_count_dict_time.start()
                              result2 = dups_count_dict(l)
                              dups_count_dict_time.stop()
                      
                              dups_count_counter.start()
                              result3 = dups_counter(l)
                              dups_count_counter.stop()
                      
                              assert_equal_results(result1, result2, result3)
                      
                          print 'dups_count: %.3f' % dups_count_time.get_time_sum()
                          print 'dups_count_dict: %.3f' % dups_count_dict_time.get_time_sum()
                          print 'dups_count_counter: %.3f' % dups_count_counter.get_time_sum()
                      

                      【讨论】:

                        【解决方案24】:

                        使用toolz时:

                        from toolz import frequencies, valfilter
                        
                        a = [1,2,2,3,4,5,4]
                        >>> list(valfilter(lambda count: count > 1, frequencies(a)).keys())
                        [2,4] 
                        

                        【讨论】:

                          【解决方案25】:

                          我进入这个讨论的时间很晚。尽管如此,我想用一个衬垫来处理这个问题。因为这就是 Python 的魅力所在。 如果我们只想将重复项放入单独的列表(或任何集合)中,我建议按照以下方式进行操作。假设我们有一个重复的列表,我们可以将其称为“目标”

                              target=[1,2,3,4,4,4,3,5,6,8,4,3]
                          

                          现在如果我们想得到重复的,我们可以使用下面的一个衬垫:

                              duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))
                          

                          此代码会将重复的记录作为键并将计数作为值放入字典'duplicates'中。'duplicate'字典如下所示:

                              {3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times
                          

                          如果您只希望列表中包含重复的所有记录,那么它的代码又要短得多:

                              duplicates=filter(lambda rec : target.count(rec)>1,target)
                          

                          输出将是:

                              [3, 4, 4, 4, 3, 4, 3]
                          

                          这在 python 2.7.x + 版本中完美运行

                          【讨论】:

                            【解决方案26】:

                            方法一:

                            list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))
                            

                            解释: [val for idx, val in enumerate(input_list) if val in input_list[idx+1:]] 是一个列表推导式,它返回一个元素,如果相同的元素从它的当前位置出现,在列表中,索引。

                            示例: input_list = [42,31,42,31,3,31,31,5,6,6,6,6,6,7,42]

                            从列表中的第一个元素 42 开始,索引为 0,它检查元素 42 是否存在于 input_list[1:] 中(即,从索引 1 到列表末尾) 因为 42 存在于 input_list[1:] 中,所以它会返回 42。

                            然后它转到下一个元素 31,索引为 1,并检查元素 31 是否存在于 input_list[2:] 中(即,从索引 2 到列表末尾), 因为 31 存在于 input_list[2:] 中,所以它将返回 31。

                            类似地,它会遍历列表中的所有元素,并且只会将重复/重复的元素返回到列表中。

                            然后因为我们有重复,在一个列表中,我们需要在每个重复项中选择一个,即删除重复项中的重复项,为此,我们确实调用了一个名为 set() 的 python 内置函数,它会删除重复,

                            然后我们得到一个集合,但不是列表,因此为了从集合转换为列表,我们使用类型转换 list(),并将元素集合转换为列表。

                            方法二:

                            def dupes(ilist):
                                temp_list = [] # initially, empty temporary list
                                dupe_list = [] # initially, empty duplicate list
                                for each in ilist:
                                    if each in temp_list: # Found a Duplicate element
                                        if not each in dupe_list: # Avoid duplicate elements in dupe_list
                                            dupe_list.append(each) # Add duplicate element to dupe_list
                                    else: 
                                        temp_list.append(each) # Add a new (non-duplicate) to temp_list
                            
                                return dupe_list
                            

                            解释: 在这里,我们首先创建两个空列表。 然后继续遍历列表的所有元素,看看它是否存在于 temp_list 中(最初为空)。如果它不在 temp_list 中,那么我们使用 append 方法将它添加到 temp_list 中。

                            如果它已经存在于 temp_list 中,则意味着列表的当前元素是重复的,因此我们需要使用 append 方法将其添加到 dupe_list 中。

                            【讨论】:

                              【解决方案27】:
                              raw_list = [1,2,3,3,4,5,6,6,7,2,3,4,2,3,4,1,3,4,]
                              
                              clean_list = list(set(raw_list))
                              duplicated_items = []
                              
                              for item in raw_list:
                                  try:
                                      clean_list.remove(item)
                                  except ValueError:
                                      duplicated_items.append(item)
                              
                              
                              print(duplicated_items)
                              # [3, 6, 2, 3, 4, 2, 3, 4, 1, 3, 4]
                              

                              您基本上通过转换为集合 (clean_list) 来删除重复项,然后迭代 raw_list,同时删除干净列表中的每个 item 以在 raw_list 中出现。如果未找到item,则会捕获引发的ValueError 异常并将item 添加到duplicated_items 列表中。

                              如果需要重复项的索引,只需enumerate 列表并使用索引。 (for index, item in enumerate(raw_list):) 更快,并且针对大型列表(如数千个元素)进行了优化

                              【讨论】:

                                【解决方案28】:

                                在列表中使用list.count()方法找出给定列表的重复元素

                                arr=[]
                                dup =[]
                                for i in range(int(input("Enter range of list: "))):
                                    arr.append(int(input("Enter Element in a list: ")))
                                for i in arr:
                                    if arr.count(i)>1 and i not in dup:
                                        dup.append(i)
                                print(dup)
                                

                                【讨论】:

                                • 使用计数函数查找列表中重复元素的简单方法
                                【解决方案29】:

                                单行,为了好玩,需要一个语句。

                                (lambda iterable: reduce(lambda (uniq, dup), item: (uniq, dup | {item}) if item in uniq else (uniq | {item}, dup), iterable, (set(), set())))(some_iterable)
                                

                                【讨论】:

                                  【解决方案30】:

                                  我想在列表中查找重复项的最有效方法是:

                                  from collections import Counter
                                  
                                  def duplicates(values):
                                      dups = Counter(values) - Counter(set(values))
                                      return list(dups.keys())
                                  
                                  print(duplicates([1,2,3,6,5,2]))
                                  

                                  它对所有元素使用一次Counter,然后对所有唯一元素使用一次。用第二个减去第一个将只删除重复项。

                                  【讨论】:

                                    猜你喜欢
                                    • 1970-01-01
                                    • 1970-01-01
                                    • 2016-05-18
                                    • 2020-07-21
                                    • 2013-04-14
                                    • 1970-01-01
                                    • 2019-07-28
                                    • 2020-07-30
                                    相关资源
                                    最近更新 更多