Come posso trovare i duplicati in un elenco Python e creare un altro elenco dei duplicati? L'elenco contiene solo numeri interi.
Come posso trovare i duplicati in un elenco Python e creare un altro elenco dei duplicati? L'elenco contiene solo numeri interi.
Risposte:
Per rimuovere i duplicati utilizzare set(a)
. Per stampare duplicati, qualcosa del tipo:
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]
Si noti che Counter
non è particolarmente efficiente ( tempistiche ) e probabilmente eccessivo qui. set
si esibirà meglio. Questo codice calcola un elenco di elementi univoci nell'ordine di origine:
seen = set()
uniq = []
for x in a:
if x not in seen:
uniq.append(x)
seen.add(x)
o, più concisamente:
seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]
Non consiglio quest'ultimo stile, perché non è ovvio cosa not seen.add(x)
stia facendo (il add()
metodo set ritorna sempre None
, quindi la necessità di not
).
Per calcolare l'elenco di elementi duplicati senza librerie:
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
Se gli elementi dell'elenco non sono cancellabili, non è possibile utilizzare set / dicts e ricorrere a una soluzione temporale quadratica (confrontarli con ciascuno). Per esempio:
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)
, perché scorre una volta sola la lista e lo sono le ricerche impostate O(1)
.
dup = []
else: dup.append(x)
print()
seen = set()
quindidupe = 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
con set(l)
riduce solo la complessità del tempo peggiore e quindi non fa nulla per affrontare i problemi di efficienza su larga scala con questa risposta. Probabilmente non era poi così semplice. In breve, non farlo.
Non è necessario il conteggio, solo se l'oggetto è stato visto o meno prima. Adattato quella risposta a questo problema:
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]
Nel caso in cui la velocità sia importante, ecco alcuni tempi:
# 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
Ecco i risultati: (ben fatto @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
È interessante notare che, oltre ai tempi stessi, anche la classifica cambia leggermente quando viene usato pypy. Cosa più interessante, l'approccio Counter-based beneficia enormemente delle ottimizzazioni di pypy, mentre l'approccio di caching del metodo che ho suggerito sembra non avere quasi alcun effetto.
$ 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
Apparentemente questo effetto è legato alla "duplicazione" dei dati di input. Ho impostato l = [random.randrange(1000000) for i in xrange(10000)]
e ottenuto questi risultati:
$ 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
ogni volta che sarebbe necessario un inserimento.
pypy
se lo hai a portata di mano e stai andando veloce.
Puoi usare iteration_utilities.duplicates
:
>>> from iteration_utilities import duplicates
>>> list(duplicates([1,1,2,1,2,3,4,2]))
[1, 1, 2, 2]
o se vuoi solo uno di ogni duplicato, questo può essere combinato con iteration_utilities.unique_everseen
:
>>> from iteration_utilities import unique_everseen
>>> list(unique_everseen(duplicates([1,1,2,1,2,3,4,2])))
[1, 2]
Può anche gestire elementi non lavabili (comunque a costo di prestazione):
>>> list(duplicates([[1], [2], [1], [3], [1]]))
[[1], [1]]
>>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
[[1]]
Questo è qualcosa che solo alcuni degli altri approcci qui possono gestire.
Ho fatto un rapido benchmark contenente la maggior parte (ma non tutti) degli approcci citati qui.
Il primo benchmark includeva solo una piccola gamma di lunghezze di elenco perché alcuni approcci hanno un O(n**2)
comportamento.
Nei grafici l'asse y rappresenta il tempo, quindi un valore più basso significa migliore. È anche tracciato log-log in modo da poter visualizzare meglio l'ampia gamma di valori:
Rimuovendo gli O(n**2)
approcci ho fatto un altro benchmark fino a mezzo milione di elementi in un elenco:
Come puoi vedere, l' iteration_utilities.duplicates
approccio è più veloce di qualsiasi altro approccio e persino il concatenamento è unique_everseen(duplicates(...))
stato più veloce o altrettanto veloce degli altri approcci.
Un'altra cosa interessante da notare qui è che gli approcci dei panda sono molto lenti per elenchi di piccole dimensioni ma possono facilmente competere per elenchi più lunghi.
Tuttavia, dal momento che questi benchmark mostrano che la maggior parte degli approcci si comporta approssimativamente allo stesso modo, quindi non importa molto quale viene utilizzato (tranne per i 3 che hanno O(n**2)
runtime).
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 Questo è da una libreria di terze parti che ho scritto: iteration_utilities
.
Mi sono imbattuto in questa domanda mentre cercavo qualcosa di simile - e mi chiedo perché nessuno offrisse una soluzione basata su un generatore? Risolvere questo problema sarebbe:
>>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
[1, 2, 5]
Mi occupavo della scalabilità, quindi ho testato diversi approcci, inclusi elementi ingenui che funzionano bene su elenchi di piccole dimensioni, ma scalano orribilmente man mano che gli elenchi diventano più grandi (nota: sarebbe stato meglio usare timeit, ma questo è illustrativo).
Ho incluso @moooeeeep per il confronto (è incredibilmente veloce: più veloce se l'elenco di input è completamente casuale) e un approccio itertools che è ancora più veloce per gli elenchi per lo più ordinati ... Ora include l'approccio panda da @firelynx - lento, ma non orribilmente così e semplice. Nota: l'approccio sort / tee / zip è costantemente più veloce sulla mia macchina per grandi elenchi per lo più ordinati, moooeeeep è più veloce per gli elenchi mescolati, ma il tuo chilometraggio può variare.
vantaggi
ipotesi
Soluzione più veloce, voci 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
Approcci testati
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
I risultati del test "tutti i duplicati" sono stati coerenti, trovando i duplicati "prima" e poi "tutti" in questo array:
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
Quando le liste vengono mescolate per prime, il prezzo dell'ordinamento diventa evidente: l'efficienza diminuisce notevolmente e l'approccio @moooeeeep domina, con gli approcci di set & dict che sono simili ma i performer minori:
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)
conto. Inoltre, non riesco a replicare i tuoi risultati nemmeno quando eseguo lo script inalterato (ordinamento totalmente diverso), quindi forse dipende anche dalla CPU.
collezioni.Counter è nuovo in 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'
>>>
In una versione precedente puoi invece usare un dict convenzionale:
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]
Ecco una soluzione chiara e concisa:
for x in set(li):
li.remove(x)
li = list(set(li))
Senza la conversione in elenco e probabilmente il modo più semplice sarebbe qualcosa di simile di seguito. Questo può essere utile durante un'intervista quando chiedono di non usare i set
a=[1,2,3,3,3]
dup=[]
for each in a:
if each not in dup:
dup.append(each)
print(dup)
======= altro per ottenere 2 elenchi separati di valori univoci e valori duplicati
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)
Lo farei con i panda, perché uso molto i panda
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()
dà
[3,6]
Probabilmente non è molto efficiente, ma è sicuramente meno codice di molte altre risposte, quindi ho pensato di contribuire
pda = pd.Series(a)
print list(pda[pda.duplicated()])
il terzo esempio della risposta accettata fornisce una risposta errata e non tenta di fornire duplicati. Ecco la versione corretta:
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
Che ne dite semplicemente di scorrere ogni elemento nell'elenco controllando il numero di occorrenze, quindi aggiungendole a un set che stamperà i duplicati. Spero che questo aiuti qualcuno là fuori.
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]
Possiamo usare itertools.groupby
per trovare tutti gli oggetti che hanno duplicati:
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
L'output sarà:
4
6
dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
Immagino che il modo più efficace per trovare duplicati in un elenco sia:
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]))
Usa Counter
tutti gli elementi e tutti gli elementi unici. Sottraendo il primo con il secondo si tralasciano solo i duplicati.
Un po 'in ritardo, ma forse utile per alcuni. Per un elenco di grandi dimensioni, ho trovato che ha funzionato per me.
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]
Mostra solo e tutti i duplicati e conserva l'ordine.
Il modo molto semplice e rapido per trovare duplicati con una iterazione in Python è:
testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']
testListDict = {}
for item in testList:
try:
testListDict[item] += 1
except:
testListDict[item] = 1
print testListDict
L'output sarà il seguente:
>>> print testListDict
{'blue': 3, 'green': 1, 'red': 2}
Questo e altro nel mio blog http://www.howtoprogramwithpython.com
Sto entrando molto tardi in questa discussione. Anche se, vorrei affrontare questo problema con una fodera. Perché questo è il fascino di Python. se vogliamo solo inserire i duplicati in un elenco separato (o in qualsiasi raccolta), suggerirei di fare come di seguito. Diciamo che abbiamo un elenco duplicato che possiamo chiamare come "target"
target=[1,2,3,4,4,4,3,5,6,8,4,3]
Ora, se vogliamo ottenere i duplicati, possiamo usare un solo liner come di seguito:
duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))
Questo codice inserirà i record duplicati come chiave e conterà come valore nel dizionario "duplicati". Il dizionario "duplicato" sarà simile al seguente:
{3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times
Se vuoi solo tutti i record con i duplicati da soli in un elenco, è di nuovo un codice molto più breve:
duplicates=filter(lambda rec : target.count(rec)>1,target)
L'output sarà:
[3, 4, 4, 4, 3, 4, 3]
Funziona perfettamente nelle versioni python 2.7.x +
Python 3.8 one-liner se non ti interessa scrivere il tuo algoritmo o utilizzare le librerie:
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)
Stampa l'elemento e conta:
[(1, 2), (2, 2), (5, 4)]
groupby
accetta una funzione di raggruppamento in modo da poter definire i raggruppamenti in diversi modi e restituire Tuple
campi aggiuntivi , se necessario.
groupby
è pigro, quindi non dovrebbe essere troppo lento.
Alcuni altri test. Certo da fare ...
set([x for x in l if l.count(x) > 1])
... è troppo costoso. È circa 500 volte più veloce (l'array più lungo offre risultati migliori) per utilizzare il prossimo metodo finale:
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()
Solo 2 anelli, nessuna l.count()
operazione molto costosa .
Ecco un codice per confrontare i metodi, ad esempio. Il codice è sotto, ecco l'output:
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
Il codice di test:
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()
Metodo 1:
list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))
Spiegazione: [val per idx, val in enumerate (input_list) se val in input_list [idx + 1:]] è una comprensione dell'elenco, che restituisce un elemento, se lo stesso elemento è presente dalla sua posizione corrente, nell'elenco, l'indice .
Esempio: input_list = [42,31,42,31,3,31,31,5,6,6,6,6,6,7,42]
a partire dal primo elemento nell'elenco, 42, con l'indice 0, controlla se l'elemento 42 è presente in input_list [1:] (ovvero dall'indice 1 fino alla fine dell'elenco) Perché 42 è presente in input_list [1:] , restituirà 42.
Quindi passa all'elemento 31 successivo, con l'indice 1, e controlla se l'elemento 31 è presente in input_list [2:] (cioè dall'indice 2 fino alla fine dell'elenco), poiché 31 è presente in input_list [2:], restituirà 31.
allo stesso modo passa attraverso tutti gli elementi dell'elenco e restituirà solo gli elementi ripetuti / duplicati in un elenco.
Quindi, poiché abbiamo duplicati, in un elenco, dobbiamo scegliere uno di ciascun duplicato, ovvero rimuovere duplicati tra duplicati e, per fare ciò, chiamiamo un set di pitone incorporato chiamato (), e rimuove i duplicati,
Quindi ci rimane un set, ma non un elenco, e quindi per convertire da un set a list, usiamo, typecasting, list () e che converte il set di elementi in un elenco.
Metodo 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
Spiegazione: Qui creiamo due elenchi vuoti, per cominciare. Quindi continua a spostarti tra tutti gli elementi dell'elenco, per vedere se esiste in temp_list (inizialmente vuoto). Se non è presente nell'elenco temp_, quindi lo aggiungiamo all'elenco temp_ usando il metodo append .
Se esiste già in temp_list, significa che l'elemento corrente dell'elenco è un duplicato e quindi dobbiamo aggiungerlo a dupe_list usando il metodo 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]
Fondamentalmente si rimuovono i duplicati convertendoli in set ( clean_list
), quindi si esegue l'iterazione di raw_list
, rimuovendo ciascuno item
nell'elenco pulito per occorrenza in raw_list
. Se item
non viene trovato, l' ValueError
eccezione sollevata viene rilevata e item
aggiunta aduplicated_items
all'elenco.
Se è necessario l'indice degli elementi duplicati, basta enumerate
l'elenco e giocare con l'indice. ( for index, item in enumerate(raw_list):
) che è più veloce e ottimizzato per elenchi di grandi dimensioni (come migliaia + di elementi)
uso del list.count()
metodo nell'elenco per scoprire gli elementi duplicati di un determinato elenco
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)
Ci sono molte risposte qui, ma penso che questo sia un approccio relativamente molto leggibile e di facile comprensione:
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)
Appunti:
Ecco un generatore veloce che utilizza un dict per memorizzare ogni elemento come chiave con un valore booleano per verificare se l'articolo duplicato è già stato prodotto.
Per gli elenchi con tutti gli elementi che sono tipi hash:
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]
Per elenchi che potrebbero contenere elenchi:
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]))
Quando si utilizza 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]
questo è il modo in cui ho dovuto farlo perché mi sono sfidato a non usare altri metodi:
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
quindi il tuo campione funziona come:
>>>a = [1,2,3,3,3,4,5,6,6,7]
>>>dupList(a)
[1, 2, 3, 4, 5, 6, 7]
duplist = list(set(a))
.