ChatGPT解决这个技术问题 Extra ChatGPT

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

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

你想要重复一次,还是每次再次看到它?
我认为这里已经以更高的效率回答了这个问题。 stackoverflow.com/a/642919/1748045 交集是一种内置的 set 方法,应该完全符合要求

1
12 revs, 8 users 71%

要删除重复项,请使用 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) 在做什么并不明显(set 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() 中用括号调用
将您对 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])
M
Mateen Ulhaq

一个非常简单的解决方案,但复杂度为 O(n*n)。

>>> xs = [1,2,3,4,4,5,5,6,1]
>>> set([x for x in xs if xs.count(x) > 1])
set([1, 4, 5])

你有什么理由使用列表推导而不是生成器推导?
事实上,一个简单的解决方案,但复杂性是平方的,因为每个 count() 都会重新解析列表,所以不要用于大型列表。
@JohnJ,冒泡排序也很简单并且有效。这并不意味着我们应该使用它!
@watsonic:在一般情况下,您的“简单开关”未能将时间复杂度从平方降低到平方。将 l 替换为 set(l) 只会降低最坏情况的时间复杂度,因此 没有 解决此答案的大规模效率问题。毕竟可能没那么简单。简而言之,不要这样做。
不要这样做。
C
Community

您不需要计数,只需要之前是否看到过该项目。使 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

只是好奇- see_add = seen.add 的目的是什么?
@Rob 这样,您只需调用您之前查找过的函数。否则,每次需要插入时,您都需要查找(字典查询)成员函数 add
用我自己的数据和 Ipython 的 %timeit 检查您的方法在测试中看起来确实最快,但是:“最慢的运行时间比最快的运行时间长 4.34 倍。这可能意味着正在缓存中间结果”
@moooeeeeep,我在您的脚本中添加了另一个版本供您尝试 :) 如果您手头方便并且想要加快速度,也可以尝试 pypy
@JohnLaRooy 性能提升不错!有趣的是,当我使用 pypy 评估结果时,基于计数器的方法显着提高。
M
MSeifert

您可以使用 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 轴代表时间,因此值越低越好。它还绘制了对数对数,因此可以更好地可视化广泛的值:

https://i.stack.imgur.com/jjz5n.png

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

https://i.stack.imgur.com/rGuBC.png

如您所见,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) 保存了我的)并删除了实际情节周围的大部分空白。然后图像更大更清晰,无论是在嵌入视图中还是在独立视图中(单击图像时)。较高的分辨率会增加文件大小,但您可以通过减少颜色深度来解决这个问题。
F
F1Rumors

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

>>> 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  

当列表首先被洗牌时,排序的代价变得明显——效率明显下降,@moooeeeep 方法占主导地位,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  

@moooeeeeep - 有兴趣了解您对 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)
w
wellplayed

使用熊猫:

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

N
Nikhil Prabhu

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

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

li = list(set(li))

但是,原始列表丢失了。这可以通过将内容复制到另一个列表来解决 - temp = li[:]
这对大型列表来说是一个非常讨厌的练习——从列表中删除元素非常昂贵!
y
yǝsʞǝla

如果您不想编写自己的算法或使用库,请使用 Python 3.8 单线:

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

res = [(x, count) for x, g in groupby(sorted(l)) if (count := len(list(g))) > 1]

print(res)

打印项目和计数:

[(1, 2), (2, 2), (5, 4)]

groupby 采用分组功能,因此您可以以不同方式定义分组并根据需要返回额外的 Tuple 字段。


惰性与速度无关(就吞吐量而言),尤其是在 res 是一个列表的情况下,这是急切的。
这很棒,但应该提到您需要 from itertools import groupby
g
georg

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]

f
firelynx

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

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()])
H
HenryDev

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

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]

A
A. Kali

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

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,然后对所有唯一元素使用一次。用第二个减去第一个将只留下重复项。


N
Nir Alfasi

我们可以使用 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]
y
yota

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

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

C
Chetan_Vasudevan

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

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”后,有人会做什么?
u
user3109122

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

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]

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


I
Igor Vishnevskiy

在 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


这是桶排序的一种变体。
a
akhil pathirippilly

我进入这个讨论的时间很晚。尽管如此,我想用一个衬垫来处理这个问题。因为这就是 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 + 版本中完美运行


s
superb rain

尽管它的复杂度为 O(n log n),但这似乎有些竞争,请参阅下面的基准。

a = sorted(a)
dupes = list(set(a[::2]) & set(a[1::2]))

排序使重复项彼此相邻,因此它们都位于偶数索引和奇数索引处。唯一值仅位于偶数或奇数索引处,而不是两者。所以偶数索引值和奇数索引值的交集是重复的。

https://i.stack.imgur.com/heK8B.png

这使用 MSeifert's benchmark,但仅使用来自已接受答案(georgs)的解决方案、最慢的解决方案、最快的解决方案(不包括 it_duplicates,因为它不会唯一化重复项)和我的解决方案。否则它会太拥挤,颜色太相似。

如果允许我们修改给定的列表,第一行可能是 a.sort(),这样会快一些。但是基准测试多次重复使用同一个列表,因此修改它会弄乱基准测试。

显然 set(a[::2]).intersection(a[1::2]) 不会创建第二组并且会更快一些,但是嗯,它也有点长。


考虑到复杂性,这是所有解决方案中最好的。谢谢!
S
Sundeep471

方法一:

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 中。


s
sergzach

其他一些测试。当然要做...

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()

A
All Іѕ Vаиітy
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):) 更快,并且针对大型列表(如数千个元素)进行了优化


R
Ravikiran D

在列表中使用 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)

使用计数函数在列表中查找重复元素的简单方法
W
Wizr

单线,为了好玩,并且需要一个单一的声明。

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

H
Haresh Shyara
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)

r
rassa45

一线解决方案:

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

t
tvt173

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

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 语句(您可以稍后设置)


J
John B

这是一个快速生成器,它使用 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]

A
Andreas Profous

使用 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] 

A
Artier

试试这个检查重复项

>>> 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 或其他导入不可用)。