목록에서 중복 항목을 찾고 다른 목록을 만들려면 어떻게해야합니까?


437

Python 목록에서 중복 항목을 찾고 다른 중복 목록을 만들려면 어떻게해야합니까? 이 목록에는 정수만 포함됩니다.



1
복제본을 한 번 또는 다시 볼 때마다 원하십니까?
moooeeeep

나는 이것이 훨씬 많은 효율성으로 대답했다고 생각합니다. stackoverflow.com/a/642919/1748045 교차점은 내장 된 설정 방법이며 필요한 것을 정확하게 수행해야합니다.
Tom Smith

답변:


545

중복을 제거하려면을 사용하십시오 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특히 효율적인 (없는 타이밍 아마 과잉 여기)합니다. 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 = {}
dupes = []

for x in a:
    if x not in seen:
        seen[x] = 1
    else:
        if seen[x] == 1:
            dupes.append(x)
        seen[x] += 1

리스트 요소가 해시 가능하지 않은 경우, 세트 / 딕션을 사용할 수 없으며 2 차 시간 솔루션에 의존해야합니다 (각 요소와 비교). 예를 들면 다음과 같습니다.

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

2
@ eric : O(n)목록을 한 번만 반복하고 설정된 조회는 O(1)입니다.
georg

3
@Hugo, 중복 목록을 보려면 dup이라는 새 목록을 만들고 else 문을 추가하면됩니다. 예 :dup = [] else: dup.append(x)
Chris Nielsen

4
@oxeimon : 아마도 이것을 얻었을 수도 있지만, 파이썬 3에서 괄호로 인쇄됩니다.print()
Moberg

4
set ()에 대한 답변을 중복으로 만 변환합니다. seen = set()그때dupe = set(x for x in a if x in seen or seen.add(x))
Ta946

2
Python 3.x의 경우 : print ([항목의 항목, 모음의 수. count (1보다 크면 count (1))] (item ())
kibitzforu

327
>>> 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])

2
생성기 이해 대신 목록 이해를 사용하는 이유가 있습니까?

64
실제로 간단한 솔루션이지만 각 count ()가 목록을 다시 구문 분석하기 때문에 복잡성이 제곱되므로 큰 목록에는 사용하지 마십시오.
danuker

4
@ JohnJ, 거품 정렬도 간단하고 작동합니다. 그렇다고 우리가 사용해야한다는 의미는 아닙니다!
John La Rooy

@JohnLaRooy 실제로는 항상 효율적이고 간단한 정렬 방법이 있기 때문에 사용해서는 안된다는 의미입니다.
lostsoul29

1
@watsonic : "간단한 스위치"는 일반적인 경우에 이차에서 제곱으로 시간 복잡성을 줄이는 데 실패합니다. 교체 lset(l)않습니다 따라서 최악의 경우 시간 복잡도를 감소 만 아무 것도 이 답변에 더 큰 규모의 효율성 문제를 해결 없습니다. 아마 그렇게 간단하지 않았을 것입니다. 요컨대, 이것을하지 마십시오.
세실 카레

82

이전에 항목을 보았는지 여부에 관계없이 카운트가 필요하지 않습니다. 이 문제에 대한 답변 을 채택 했습니다 .

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

6
궁금한 점이 있습니다. seen_add = seen.add의 목적은 무엇입니까?
Rob

3
@Rob 이렇게하면 이전에 한 번 찾은 함수를 호출 할 수 있습니다. 그렇지 않으면 add삽입이 필요할 때마다 멤버 함수를 찾아야합니다 (사전 쿼리) .
moooeeeep

내 데이터와 Ipython의 % time % 테스트로 테스트 한 방법이 가장 빠르지 만 "가장 느린 실행이 가장 빠른 실행보다 4.34 배 더 오래 걸렸습니다. 이는 중간 결과가 캐시됨을 의미 할 수 있습니다"
Joop

1
@ moooeeeep, 나는 당신이 시도 할 수 있도록 스크립트에 다른 버전을 추가 pypy했습니다.
John La Rooy

@JohnLaRooy 성능이 향상되었습니다! 흥미롭게도, pypy를 사용하여 결과를 평가할 때 카운터 기반 접근 방식이 크게 향상되었습니다.
moooeeeep

42

당신은 사용할 수 있습니다 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 축은 시간을 나타내므로 값이 작을수록 좋습니다. 또한 log-log를 플로팅하여 광범위한 값을 더 잘 시각화 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

O(n**2)접근 방식을 제거하고 목록에서 최대 50 만 개의 요소를 벤치 마크했습니다.

여기에 이미지 설명을 입력하십시오

보시다시피 iteration_utilities.duplicates접근 방식은 다른 접근 방식보다 훨씬 빠릅니다.unique_everseen(duplicates(...)) 보다 빠르며 보다 빠르거나 동일합니다.

여기서 주목해야 할 또 하나의 흥미로운 점은 팬더 접근 방식이 작은 목록의 경우 속도가 느리지 만 더 긴 목록의 경우 경쟁하기 쉽다는 것입니다.

그러나 이러한 벤치 마크에서는 대부분의 접근 방식이 거의 동일하게 수행되므로 어느 것이 사용되는지는 중요하지 않습니다 ( 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.


1
나는 내 목을 여기에 내밀고 파이썬 대신 C로 작업을 수행하기 위해 맞춤형 라이브러리를 작성하도록 제안 할 것입니다. 아마도 대답의 정신이 아니었을 것입니다. 나는 답의 폭과 결과의 그래픽 표시를 좋아합니다. 결과가 수렴하는 것을 보게되어 매우 좋으며, 입력이 더 증가함에 따라 교차하는지 궁금합니다! 질문 : 완전 무작위 목록과 달리 대부분 정렬 된 목록의 결과는 무엇입니까?
F1Rumors

30

관련 질문을 보면서이 질문을 보았는데 아무도 왜 발전기 기반 솔루션을 제공하지 않았습니까? 이 문제를 해결하는 방법은 다음과 같습니다.

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

나는 확장성에 관심이 있었기 때문에 작은 목록에서 잘 작동하는 순진한 항목을 포함하여 몇 가지 접근 방식을 테스트했지만 목록이 커질수록 끔찍하게 확장됩니다 (주의는 timeit을 사용하는 것이 좋았지 만 이것은 예시 적입니다).

나는 비교를 위해 @moooeeeep (입력 목록이 완전히 임의의 경우 가장 빠름)과 itertools 접근 방식을 포함하여 대부분 정렬 된 목록에 대해 더 빠릅니다. @ firelynx의 팬더 접근 방식을 포함합니다. 끔찍하고 간단합니다. 참고-정렬 / 티 / 우편 접근 방식은 내 컴퓨터에서 주로 대부분의 정렬 된 목록에 대해 가장 빠르며, 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'테스트의 결과는 일관성이있어이 배열에서 "first"duplicate와 "all"duplicate를 찾습니다.

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  

@moooeeeep-ifilter / izip / tee 접근법에 대한 귀하의 의견을보고자합니다.
F1Rumors

1
이 답변은 믿을 수 없을만큼 훌륭합니다. 필요한 사람들에게 매우 유용한 설명과 테스트에 더 많은 포인트가 없었 음을 이해하지 못합니다.
dlewin

1
python의 정렬은 하나의 항목 만 고장난 경우 O (n)입니다. 당신은 random.shuffle(c)그것을 설명 해야 합니다. 또한 변경되지 않은 스크립트를 실행할 때 (완전히 다른 순서로) 결과를 복제 할 수 없으므로 CPU에도 의존 할 수 있습니다.
John La Rooy

@ John-La-Rooy에게 감사드립니다. CPU / 로컬 시스템에 영향을주는 것을 잘 관찰하십시오. 따라서 YYMV 항목을 수정해야합니다 . O (n) 정렬을 사용하는 것은 의도적이었습니다. 복제 요소는 특히 다른 위치에 삽입되어 다음과 같이 좋은 (목록의 시작) 또는 나쁜 (목록의 끝) 위치에 유일한 중복이있는 경우 접근의 영향을 볼 수 있습니다 구혼. 나는 임의의 목록 (예 : random.shuffle)을 고려했지만 더 많은 달리기를 할 경우에만 합리적이라고 결정했습니다! 나는 다중 런 / 셔플에 상응하는 것을 반환하고 벤치마킹하고 그 영향이 무엇인지 확인해야한다.
F1Rumors

@firelynx pandas 접근 방식을 포함하고 완전히 섞인 목록과 정렬 된 목록에서 실행되도록 수정했습니다. 이다 파이썬에서 사용하는 기본 timsort이기 때문에 악한 대부분 정렬 된 데이터에 대한 고속 (최고 경우)와 뒤섞 목록은 최악의 시나리오입니다 - 결과까지 쉐이크가.
F1Rumors

13

팬더 사용하기 :

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

10

카운터는 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]

9

깔끔하고 간결한 솔루션은 다음과 같습니다.

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

li = list(set(li))

그러나 원래 목록은 손실됩니다. 이것은 다른 목록으로 내용을 복사함으로써 고칠 수 있습니다-temp = li [:]
Nikhil Prabhu

3
그것은 큰 목록에서 상당히 불쾌한 연습입니다-목록에서 요소를 제거하는 것은 꽤 비쌉니다!
F1Rumors

7

목록으로 변환하지 않고 가장 간단한 방법은 다음과 같습니다. 인터뷰를 할 때 세트를 사용하지 말라고 할 때 유용 할 수 있습니다.

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

======= 그렇지 않으면 두 개의 고유 값과 중복 값으로 구성된 두 개의 개별 목록을 얻습니다.

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)

1
이것은 (또는 원래 목록)의 중복 목록을 생성하지는 않지만 (또는 원래 목록)의 모든 고유 요소 목록을 생성합니다. "dup"목록을 완성한 후에는 어떻게합니까?
gameCoder95

6

팬더를 많이 사용하기 때문에 팬더 로이 작업을 수행합니다.

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]

아마도 매우 효율적이지는 않지만 다른 많은 답변보다 코드가 적기 때문에 기여할 것이라고 생각했습니다.


3
팬더가 내장 된 중복 기능이 포함되어 있음을 유의하십시오 pda = pd.Series(a) print list(pda[pda.duplicated()])
렌 Blokken

6

허용되는 답변의 세 번째 예는 잘못된 답변을 제공하고 중복을 제공하지 않습니다. 올바른 버전은 다음과 같습니다.

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

6

어커런스 수를 확인한 다음 세트에 추가하여 복제본을 인쇄하여 목록의 각 요소를 간단하게 반복하는 방법은 무엇입니까? 이것이 누군가를 도울 수 있기를 바랍니다.

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]

5

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

1
더 간결하게 :dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
frnhr

5

목록에서 중복을 찾는 가장 효과적인 방법은 다음과 같습니다.

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모든 요소와 모든 고유 요소를. 첫 번째 것을 두 번째로 빼면 복제본 만 남습니다.


4

조금 늦었지만 일부에게는 도움이 될 수 있습니다. 게으른 목록의 경우 이것이 효과가 있음을 알았습니다.

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]

모든 복제본 만 표시하고 순서를 유지합니다.


3

파이썬에서 한 번의 반복으로 듀피를 찾는 매우 간단하고 빠른 방법은 다음과 같습니다.

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 에서이 이상


3

이 토론에 훨씬 늦게 들어갑니다. 그럼에도 불구하고 하나의 라이너 로이 문제를 해결하고 싶습니다. 그것이 파이썬의 매력이기 때문입니다. 중복을 별도의 목록 (또는 컬렉션)에 가져 오려면 다음과 같이 제안하십시오. 중복 목록을 가지고 '대상'이라고 부를 수 있습니다

    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]

이것은 파이썬 2.7.x + 버전에서 완벽하게 작동합니다.


3

자체 알고리즘을 작성하거나 라이브러리를 사용하지 않아도되는 Python 3.8 one-liner :

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 하고 필요에 따라 필드를 .

groupby 게 으르므로 너무 느려서는 안됩니다.


2

다른 테스트들. 물론 ...

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

너무 비싸다. 다음 최종 방법을 사용하면 약 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()

2

방법 1 :

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

설명: [idx에 대한 val, input_list [idx + 1 :]의 val 인 경우 enumerate (input_list)의 val은 목록 이해입니다. 동일한 요소가 현재 위치, 목록, 색인에서 존재하는 경우 요소를 리턴 함) .

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

리스트 0의 첫 번째 요소 인 인덱스 0부터 시작하여, 요소 42가 input_list [1 :]에 있는지 (즉, 인덱스 1에서 목록 끝까지) 42가 input_list [1 :]에 있기 때문에 확인합니다. 42를 반환합니다.

그런 다음 인덱스 1이있는 다음 요소 31로 이동하여 요소 31이 input_list [2 :]에 있는지 (즉, 인덱스 2에서 목록 끝까지) 31이 input_list [2 :]에 있는지 확인합니다. 31을 반환합니다.

마찬가지로 목록의 모든 요소를 ​​거치며 반복 / 중복 된 요소 만 목록으로 반환합니다.

그런 다음 목록에 중복이 있기 때문에 각 중복 중 하나를 선택해야합니다. 즉 중복 중에서 중복을 제거하고 그렇게하려면 파이썬 내장 내장 set ()을 호출하고 중복을 제거합니다.

그런 다음 목록이 아닌 세트로 남아 있으므로 세트에서 목록으로 변환하기 위해 typecasting, list ()를 사용하여 요소 세트를 목록으로 변환합니다.

방법 2 :

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에 추가해야한다는 의미 입니다.


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

기본적으로 set ( clean_list) 으로 변환하여 중복을 제거한 다음 에서 정리 목록에서 raw_list각각을 제거 하면서을 반복합니다 . 경우 발견되지 않은, 제기 예외가 적발되고이 추가됩니다itemraw_listitemValueErroritemduplicated_items 목록입니다.

중복 된 항목의 색인이 필요한 enumerate경우 목록 만 색인으로 재생하십시오. ( for index, item in enumerate(raw_list):수천 개 이상의 요소와 같은) 큰 목록에 더 빠르고 최적화 된


2

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)

count 함수를 사용하여 목록에서 중복 요소를 찾는 간단한 방법
Ravikiran D

2

하나의 라이너, 재미를 위해 그리고 단일 진술이 필요한 곳.

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

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


1

여기에 많은 답변이 있지만, 이것은 비교적 읽기 쉽고 이해하기 쉬운 접근법이라고 생각합니다.

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 문으로 바꿉니다 (나중에 설정하도록 캐스팅 할 수 있음)

1

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]

1
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 문은 실제로 필요하지 않습니다. 또한 솔루션과 다른 솔루션의 장점이 무엇인지 설명해야합니다.
clemens


0

이것은 다른 방법을 사용하지 말라고 스스로에게 도전했기 때문에 내가해야했던 방법입니다.

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]

3
이것은 OP가 원하는 것이 아닙니다. 그는 중복이 제거 된 목록이 아니라 중복 목록을 원했습니다. 중복이 제거 된 목록을 만들려면을 제안 duplist = list(set(a))합니다.
zondo
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.