개발/Python

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

MinorMan 2020. 9. 22. 04:44
반응형

<질문>

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


<답변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는 특히 효율적이지 않고 (타이밍) 여기에서 과도 할 수 있습니다. 세트가 더 잘 수행됩니다. 이 코드는 소스 순서의 고유 요소 목록을 계산합니다.

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

나는 후자의 스타일을 추천하지 않는다.

라이브러리없이 중복 된 요소 목록을 계산하려면 다음을 수행하십시오.

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>

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

<답변3>

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

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

분명히이 효과는 입력 데이터의 "중복성"과 관련이 있습니다. xrange (10000)에서 i에 대해 l = [random.randrange (1000000)]를 설정하고 다음과 같은 결과를 얻었습니다.

$ 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

<답변4>

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)))
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()
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에서 가져온 것입니다.


<답변5>

나는 관련된 것을 조사하는 동안이 질문을 보았습니다. 왜 아무도 발전기 기반 솔루션을 제공하지 않았는지 궁금합니다. 이 문제를 해결하는 방법은 다음과 같습니다.

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

나는 확장성에 관심이 있었기 때문에 작은 목록에서는 잘 작동하지만 목록이 커짐에 따라 끔찍하게 확장되는 순진한 항목을 포함하여 몇 가지 접근 방식을 테스트했습니다 (timeit를 사용하는 것이 더 낫지 만 이것은 예시입니다).

비교를 위해 @moooeeeep를 포함 시켰습니다 (놀랍도록 빠릅니다 : 입력 목록이 완전히 무작위이면 가장 빠름). 대부분 정렬 된 목록에 대해 다시 더 빠른 itertools 접근 방식 ... 이제 @firelynx의 pandas 접근 방식을 포함합니다. 끔찍하고 간단합니다. 참고-정렬 / 티 / 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 접근 방식이 지배적입니다.

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  

<답변6>

팬더 사용 :

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

<답변7>

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]

<답변8>

여기 깔끔하고 간결한 솔루션이 있습니다.

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

li = list(set(li))

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

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


<답변10>

자체 알고리즘을 작성하거나 라이브러리를 사용하지 않으려는 경우 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는 그룹화 함수를 사용하므로 다양한 방식으로 그룹화를 정의하고 필요에 따라 추가 튜플 필드를 반환 할 수 있습니다.

groupby는 게으 르기 때문에 너무 느려서는 안됩니다.


<답변11>

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

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)

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

발생 횟수를 확인한 다음 중복 항목을 인쇄 할 세트에 추가하여 목록의 각 요소를 반복하는 방법은 어떻습니까? 이것이 누군가를 돕기를 바랍니다.

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]

<답변14>

dups가있는 모든 항목을 찾기 위해 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

<답변15>

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

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

카운터는 모든 요소와 모든 고유 요소를 사용합니다. 첫 번째 것을 두 번째로 빼면 중복 만 제외됩니다.


<답변16>

조금 늦었지만 일부에게는 도움이 될 수 있습니다. 거대한 목록의 경우 이것이 저에게 효과적이라는 것을 알았습니다.

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]

모든 중복 항목 만 표시하고 순서를 유지합니다.


<답변17>

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에서 이것과 더 많은 것


<답변18>

나는이 토론에 훨씬 늦게 들어가고있다. 그래도이 문제를 하나의 라이너로 처리하고 싶습니다. 그것이 파이썬의 매력이기 때문입니다. 중복 된 항목을 별도의 목록 (또는 모든 컬렉션)으로 가져 오려면 다음과 같이하는 것이 좋습니다. 'target'이라고 할 수있는 중복 된 목록이 있다고 가정합니다.

    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 + 버전에서 완벽하게 작동합니다.


<답변19>

다른 테스트. 물론해야 할 일 ...

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

<답변20>

방법 1 :

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 :]] is a list comprehension, that returns an element, if the same element is present from it 's current position, in list, the index .

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

인덱스가 0 인 목록의 첫 번째 요소 42부터 시작하여 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에 추가해야합니다.


<답변21>

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를 반복하면서 raw_list에서 발생하기 위해 정리 목록에서 각 항목을 제거합니다. 항목을 찾을 수없는 경우 발생한 ValueError Exception이 포착되고 해당 항목이 duplicated_items 목록에 추가됩니다.

중복 된 항목의 색인이 필요한 경우 목록을 열거하고 색인을 가지고 놀기만하면됩니다. (인덱스의 경우 enumerate (raw_list) :)의 항목은 더 빠르고 큰 목록 (예 : 수천 개 이상의 요소)에 최적화되어 있습니다.


<답변22>

목록에서 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)

<답변23>

재미를 위해 한 줄로, 그리고 한 문장이 필요한 곳.

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

<답변24>

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)

<답변25>

한 줄 솔루션 :

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

<답변26>

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

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)

노트:

  • 중복 횟수를 유지하려면 하단의 'set'으로 캐스트를 제거하여 전체 목록을 가져옵니다.
  • 생성기를 사용하려면 duplicates.append (x)를 yield x 및 하단의 return 문으로 대체하십시오 (나중에 설정할 수 있습니다).

<답변27>

다음은 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]

<답변28>

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

<답변29>

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] 

<답변30>

다른 방법을 사용하지 말라고 스스로에게 도전했기 때문에 이렇게해야했습니다.

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]
반응형