Jak znaleźć duplikaty na liście Python i utworzyć kolejną listę duplikatów? Lista zawiera tylko liczby całkowite.
Jak znaleźć duplikaty na liście Python i utworzyć kolejną listę duplikatów? Lista zawiera tylko liczby całkowite.
Odpowiedzi:
Aby usunąć duplikaty, użyj set(a)
. Aby wydrukować duplikaty, coś takiego:
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]
Pamiętaj, że Counter
nie jest to szczególnie wydajne ( czasy ) i prawdopodobnie przesada tutaj. set
będzie działać lepiej. Ten kod oblicza listę unikalnych elementów w kolejności źródłowej:
seen = set()
uniq = []
for x in a:
if x not in seen:
uniq.append(x)
seen.add(x)
lub bardziej zwięźle:
seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]
Nie polecam tego drugiego stylu, ponieważ nie jest oczywiste, co not seen.add(x)
się dzieje ( add()
metoda set zawsze powraca None
, stąd potrzeba not
).
Aby obliczyć listę zduplikowanych elementów bez bibliotek:
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
Jeśli elementy listy nie są haszowalne, nie możesz używać zestawów / dykt i musisz uciekać się do kwadratowego rozwiązania czasowego (porównaj każdy z nich). Na przykład:
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]]
O(n)
, ponieważ iteruje listę tylko raz i ustawia wyszukiwania O(1)
.
dup = []
else: dup.append(x)
print()
seen = set()
następniedupe = set(x for x in a if x in seen or seen.add(x))
>>> 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])
l
go set(l)
tylko zmniejsza złożoność czasu najgorszego przypadku, a zatem nie robi nic, aby rozwiązać problemy związane z wydajnością na większą skalę dzięki tej odpowiedzi. To chyba nie było takie proste. Krótko mówiąc, nie rób tego.
Nie potrzebujesz liczenia, tylko czy przedmiot był wcześniej widziany. Dostosowałem tę odpowiedź do tego problemu:
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]
Na wszelki wypadek liczy się prędkość:
# 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
Oto wyniki: (dobra robota @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
Co ciekawe, oprócz samego taktowania, również ranking zmienia się nieznacznie, gdy używany jest pypy. Co najciekawsze, podejście oparte na licznikach czerpie ogromne korzyści z optymalizacji pypy, podczas gdy podejście buforowania metod, które zasugerowałem, wydaje się prawie nie mieć żadnego efektu.
$ 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
Widocznie ten efekt jest związany z „duplikacją” danych wejściowych. Ustawiłem l = [random.randrange(1000000) for i in xrange(10000)]
i otrzymałem te wyniki:
$ 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
add
każdym razem, gdy konieczne będzie wstawienie.
pypy
jeśli masz go pod ręką i idziesz na szybkość.
Możesz użyć iteration_utilities.duplicates
:
>>> from iteration_utilities import duplicates
>>> list(duplicates([1,1,2,1,2,3,4,2]))
[1, 1, 2, 2]
lub jeśli chcesz tylko jeden z każdego duplikatu, można to połączyć z iteration_utilities.unique_everseen
:
>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen(duplicates([1,1,2,1,2,3,4,2])))
[1, 2]
Może także obsługiwać elementy niewymagalne (jednak kosztem wydajności):
>>> list(duplicates([[1], [2], [1], [3], [1]]))
[[1], [1]]
>>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
[[1]]
Jest to coś, z czym poradzi sobie tylko kilka innych podejść.
Zrobiłem szybki test porównawczy zawierający większość (ale nie wszystkie) wymienionych tu podejść.
Pierwszy test porównawczy obejmował tylko niewielki zakres długości list, ponieważ niektóre podejścia mają O(n**2)
zachowanie.
Na wykresach oś y reprezentuje czas, więc niższa wartość oznacza lepiej. Jest także wykreślany log-log, dzięki czemu można lepiej wizualizować szeroki zakres wartości:
Usuwając O(n**2)
podejścia, wykonałem kolejny test porównawczy do pół miliona elementów na liście:
Jak widać, iteration_utilities.duplicates
podejście jest szybsze niż w przypadku innych podejść, a nawet tworzenie łańcuchów unique_everseen(duplicates(...))
było szybsze lub równie szybkie niż w przypadku innych podejść.
Jedną dodatkową interesującą rzeczą, którą należy tutaj zauważyć, jest to, że podejścia do pand są bardzo wolne dla małych list, ale mogą z łatwością konkurować o dłuższe listy.
Jednak ponieważ te testy porównawcze pokazują, że większość podejść działa mniej więcej równo, więc nie ma znaczenia, które z nich zostanie użyte (z wyjątkiem 3, które miały O(n**2)
czas działania).
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 Jest to z biblioteki trzeciej mam napisane: iteration_utilities
.
Natknąłem się na to pytanie, patrząc na coś powiązanego - i zastanawiam się, dlaczego nikt nie zaoferował rozwiązania opartego na generatorze? Rozwiązaniem tego problemu byłoby:
>>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
[1, 2, 5]
Martwiłem się o skalowalność, dlatego przetestowałem kilka podejść, w tym naiwne elementy, które działają dobrze na małych listach, ale skalują się strasznie, gdy listy stają się większe (uwaga - lepiej byłoby użyć timeit, ale jest to przykładowe).
Do porównania dołączyłem @moooeeeep (jest imponująco szybki: najszybszy, jeśli lista wejściowa jest całkowicie losowa) i podejście itertools, które jest jeszcze szybsze dla najczęściej posortowanych list ... Teraz obejmuje podejście pandy z @firelynx - wolno, ale nie okropnie i proste. Uwaga - podejście sort / tee / zip jest konsekwentnie najszybsze na mojej maszynie w przypadku dużych, najczęściej uporządkowanych list, moooeeeep jest najszybszy w przypadku list losowych, ale przebieg może się różnić.
Zalety
Założenia
Najszybsze rozwiązanie, 1 milion wpisów:
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
Podejścia przetestowane
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
Wyniki testu „wszystkie duplikaty” były spójne, znajdując „pierwszą” duplikat, a następnie „wszystkie” duplikaty w tej tablicy:
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
Kiedy listy są najpierw tasowane, cena tego rodzaju staje się widoczna - wydajność wyraźnie spada i dominuje podejście @moooeeeep, przy czym podejścia set & dict są podobne, ale wykonawca:
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
random.shuffle(c)
to uwzględnić. Ponadto nie mogę zreplikować twoich wyników podczas uruchamiania niezmienionego skryptu (zupełnie inna kolejność), więc może zależy to również od procesora.
collections.Counter jest nowy w Pythonie 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'
>>>
We wcześniejszej wersji można zamiast tego użyć konwencjonalnego słownika:
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]
Oto schludne i zwięzłe rozwiązanie -
for x in set(li):
li.remove(x)
li = list(set(li))
Bez konwersji na listę i prawdopodobnie najprostszym sposobem byłoby coś takiego jak poniżej. Może to być przydatne podczas wywiadu, gdy proszą o nieużywanie zestawów
a=[1,2,3,3,3]
dup=[]
for each in a:
if each not in dup:
dup.append(each)
print(dup)
======= else, aby uzyskać 2 osobne listy unikalnych wartości i zduplikowanych wartości
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)
Zrobiłbym to z pandami, ponieważ często używam pand
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()
Daje
[3,6]
Prawdopodobnie nie jest zbyt wydajny, ale z pewnością zawiera mniej kodu niż wiele innych odpowiedzi, więc pomyślałem, że mógłbym się przyłączyć
pda = pd.Series(a)
print list(pda[pda.duplicated()])
A może po prostu przejdziemy przez każdy element na liście, sprawdzając liczbę wystąpień, a następnie dodając je do zestawu, który następnie wydrukuje duplikaty. Mam nadzieję, że to pomoże komuś tam.
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]
Możemy użyć itertools.groupby
, aby znaleźć wszystkie przedmioty, które mają duplikaty:
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
Dane wyjściowe będą:
4
6
dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
Myślę, że najbardziej skutecznym sposobem na znalezienie duplikatów na liście jest:
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]))
Wykorzystuje Counter
wszystkie elementy i wszystkie unikalne elementy. Odjęcie pierwszego od drugiego spowoduje pominięcie tylko duplikatów.
Trochę późno, ale dla niektórych może być pomocny. W przypadku obszernej listy uznałem, że to zadziałało dla mnie.
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]
Pokazuje tylko i wszystkie duplikaty i zachowuje porządek.
Bardzo prosty i szybki sposób znajdowania duplikatów za pomocą jednej iteracji w Pythonie to:
testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']
testListDict = {}
for item in testList:
try:
testListDict[item] += 1
except:
testListDict[item] = 1
print testListDict
Dane wyjściowe będą następujące:
>>> print testListDict
{'blue': 3, 'green': 1, 'red': 2}
To i więcej w moim blogu http://www.howtoprogramwithpython.com
Wchodzę znacznie później w tę dyskusję. Mimo to chciałbym poradzić sobie z tym problemem za pomocą jednej wkładki. Ponieważ taki jest urok Pythona. jeśli chcemy po prostu przenieść duplikaty na osobną listę (lub dowolną kolekcję), sugeruję zrobienie tego jak poniżej. Powiedzmy, że mamy zduplikowaną listę, którą możemy nazwać „docelową”
target=[1,2,3,4,4,4,3,5,6,8,4,3]
Teraz, jeśli chcemy uzyskać duplikaty, możemy użyć jednej linijki, jak poniżej:
duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))
Ten kod umieści zduplikowane rekordy jako klucze i policzy jako wartość w słowniku „duplikaty”. Słownik „duplikatów” będzie wyglądał jak poniżej:
{3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times
Jeśli chcesz tylko wszystkich rekordów zawierających same duplikaty na liście, jego kod jest znowu znacznie krótszy:
duplicates=filter(lambda rec : target.count(rec)>1,target)
Dane wyjściowe będą:
[3, 4, 4, 4, 3, 4, 3]
Działa to doskonale w wersjach Python 2.7.x +
Jednowierszowy język Python 3.8, jeśli nie chcesz pisać własnego algorytmu lub korzystać z bibliotek:
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)
Drukuje element i liczy:
[(1, 2), (2, 2), (5, 4)]
groupby
przyjmuje funkcję grupowania, dzięki czemu można definiować grupy na różne sposoby i zwracać dodatkowe Tuple
pola w razie potrzeby.
groupby
jest leniwy, więc nie powinno być zbyt wolno.
Niektóre inne testy. Oczywiście zrobić ...
set([x for x in l if l.count(x) > 1])
... jest zbyt kosztowne. Jest około 500 razy szybszy (dłuższa tablica daje lepsze wyniki), aby zastosować następną metodę końcową:
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()
Tylko 2 pętle, bez bardzo kosztownych l.count()
operacji.
Oto kod, na przykład, aby porównać metody. Kod znajduje się poniżej, oto wynik:
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
Kod testowy:
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()
Metoda 1:
list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))
Wyjaśnienie: [val dla idx, val w wyliczeniu (lista_wejściowa), jeśli val w liście_wejściowej [idx + 1:]] jest zrozumieniem listy, która zwraca element, jeśli ten sam element jest obecny z bieżącej pozycji, na liście, indeks .
Przykład: lista_wejściowa = [42,31,42,31,3,31,31,5,6,6,6,6,6,6,7,42]
zaczynając od pierwszego elementu na liście, 42, o indeksie 0, sprawdza, czy element 42 jest obecny na liście_wejściowej [1:] (tj. od indeksu 1 do końca listy) Ponieważ 42 jest obecny na liście_wejściowej [1:] , zwróci 42.
Następnie przechodzi do następnego elementu 31 z indeksem 1 i sprawdza, czy element 31 jest obecny na liście_wejściowej [2:] (tj. Od indeksu 2 do końca listy), ponieważ 31 jest obecny na liście_wejściowej [2:], zwróci 31.
podobnie przechodzi przez wszystkie elementy na liście i zwraca tylko powtarzające się / zduplikowane elementy do listy.
Następnie, ponieważ mamy duplikaty, na liście musimy wybrać jeden z każdego duplikatu, tj. Usunąć duplikat między duplikatami, i aby to zrobić, wywołujemy wbudowany w Pythona zestaw o nazwie set (), który usuwa duplikaty,
Następnie pozostaje nam zestaw, ale nie lista, i dlatego do konwersji z zestawu na listę używamy, rzutowania czcionek, list (), i to konwertuje zestaw elementów na listę.
Metoda 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
Objaśnienie: Tutaj tworzymy na początek dwie puste listy. Następnie przechodź dalej przez wszystkie elementy listy, aby sprawdzić, czy istnieje ona w temp_list (początkowo pusta). Jeśli nie ma go na liście temp, dodajemy go do listy temp, używając metody append .
Jeśli już istnieje w temp_list, oznacza to, że bieżący element listy jest duplikatem i dlatego musimy dodać go do dupe_list przy użyciu metody append .
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]
Zasadniczo usuwasz duplikaty, konwertując na set ( clean_list
), a następnie iterujesz raw_list
, usuwając je item
z czystej listy pod kątem wystąpienia w raw_list
. Jeśli item
nie zostanie znaleziony, zgłoszony ValueError
wyjątek zostanie przechwycony i item
zostanie dodany doduplicated_items
listy.
Jeśli potrzebny jest indeks zduplikowanych elementów, wystarczy enumerate
lista i zabawa z indeksem. ( for index, item in enumerate(raw_list):
), który jest szybszy i zoptymalizowany dla dużych list (takich jak tysiące + elementów)
użycie list.count()
metody na liście, aby znaleźć duplikaty elementów danej listy
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)
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)
Tutaj jest wiele odpowiedzi, ale myślę, że jest to stosunkowo bardzo czytelne i łatwe do zrozumienia podejście:
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)
Uwagi:
Oto szybki generator, który używa słownika do przechowywania każdego elementu jako klucza z wartością logiczną do sprawdzania, czy zduplikowany element został już wydany.
W przypadku list ze wszystkimi elementami typu skrótu:
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]
W przypadku list, które mogą zawierać listy:
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]
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]))
Podczas korzystania z 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]
w ten sposób musiałem to zrobić, ponieważ rzuciłem sobie wyzwanie, aby nie używać innych metod:
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
więc twoja próbka działa jako:
>>>a = [1,2,3,3,3,4,5,6,6,7]
>>>dupList(a)
[1, 2, 3, 4, 5, 6, 7]
duplist = list(set(a))
.