¿Cómo puedo encontrar los duplicados en una lista de Python y crear otra lista de los duplicados? La lista solo contiene enteros.
¿Cómo puedo encontrar los duplicados en una lista de Python y crear otra lista de los duplicados? La lista solo contiene enteros.
Respuestas:
Para eliminar duplicados use set(a)
. Para imprimir duplicados, algo como:
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]
Tenga en cuenta que Counter
no es particularmente eficiente ( tiempos ) y probablemente exagere aquí. set
funcionará mejor. Este código calcula una lista de elementos únicos en el orden de origen:
seen = set()
uniq = []
for x in a:
if x not in seen:
uniq.append(x)
seen.add(x)
o, más concisamente:
seen = set()
uniq = [x for x in a if x not in seen and not seen.add(x)]
No recomiendo el último estilo, porque no es obvio lo que not seen.add(x)
está haciendo (el add()
método set siempre regresa None
, de ahí la necesidad denot
).
Para calcular la lista de elementos duplicados sin bibliotecas:
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
Si los elementos de la lista no son modificables, no puede usar conjuntos / dictos y debe recurrir a una solución de tiempo cuadrático (compare cada uno con cada uno). Por ejemplo:
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)
, porque solo itera la lista una vez y establece las búsquedas O(1)
.
dup = []
else: dup.append(x)
print()
seen = set()
entoncesdupe = 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)
sólo reduce el tiempo en el peor caso y por lo tanto no nada para abordar las cuestiones de eficiencia de mayor escala con esta respuesta. Probablemente no fue tan simple después de todo. En resumen, no hagas esto.
No necesita el recuento, solo si el artículo se vio o no antes. Adaptado esa respuesta a este 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]
En caso de que la velocidad sea importante, aquí hay algunos tiempos:
# 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
Aquí están los resultados: (¡bien hecho @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
Curiosamente, además de los tiempos en sí, también la clasificación cambia ligeramente cuando se usa pypy. Lo más interesante es que el enfoque basado en el contador se beneficia enormemente de las optimizaciones de pypy, mientras que el método de almacenamiento en caché del método que he sugerido parece no tener casi ningún efecto.
$ 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
Aparentemente, este efecto está relacionado con la "duplicación" de los datos de entrada. He configurado l = [random.randrange(1000000) for i in xrange(10000)]
y obtuve estos resultados:
$ 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
cada vez que fuera necesaria una inserción.
pypy
si lo tienes a mano y buscas velocidad.
Puedes usar iteration_utilities.duplicates
:
>>> from iteration_utilities import duplicates
>>> list(duplicates([1,1,2,1,2,3,4,2]))
[1, 1, 2, 2]
o si solo quieres uno de cada duplicado, esto se puede combinar 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]
También puede manejar elementos no compartibles (sin embargo, a costa del rendimiento):
>>> list(duplicates([[1], [2], [1], [3], [1]]))
[[1], [1]]
>>> list(unique_everseen(duplicates([[1], [2], [1], [3], [1]])))
[[1]]
Eso es algo que solo algunos de los otros enfoques aquí pueden manejar.
Hice un punto de referencia rápido que contiene la mayoría (pero no todos) de los enfoques mencionados aquí.
El primer punto de referencia incluyó solo un pequeño rango de longitudes de lista porque algunos enfoques tienen O(n**2)
comportamiento.
En los gráficos, el eje y representa el tiempo, por lo que un valor más bajo significa mejor. También se traza log-log para que se pueda visualizar mejor la amplia gama de valores:
Eliminando los O(n**2)
enfoques, hice otro punto de referencia de hasta medio millón de elementos en una lista:
Como puede ver, el iteration_utilities.duplicates
enfoque es más rápido que cualquiera de los otros enfoques e incluso encadenamientounique_everseen(duplicates(...))
fue más rápido o igual de rápido que los otros enfoques.
Una cosa interesante adicional a tener en cuenta aquí es que los enfoques de los pandas son muy lentos para listas pequeñas, pero pueden competir fácilmente por listas más largas.
Sin embargo, como muestran estos puntos de referencia, la mayoría de los enfoques tienen un rendimiento aproximadamente igual, por lo que no importa mucho cuál se use (excepto los 3 que tuvieron O(n**2)
tiempo de ejecución).
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 Se trata de una biblioteca de terceros que he escrito: iteration_utilities
.
Me encontré con esta pregunta mientras buscaba algo relacionado, y me pregunto por qué nadie ofreció una solución basada en un generador. Resolver este problema sería:
>>> print list(getDupes_9([1,2,3,2,1,5,6,5,5,5]))
[1, 2, 5]
Estaba preocupado por la escalabilidad, por lo que probé varios enfoques, incluidos elementos ingenuos que funcionan bien en listas pequeñas, pero escalan horriblemente a medida que las listas se hacen más grandes (nota: habría sido mejor usar timeit, pero esto es ilustrativo).
Incluí @moooeeeep para la comparación (es impresionantemente rápido: más rápido si la lista de entrada es completamente aleatoria) y un enfoque de itertools que es aún más rápido nuevamente para listas en su mayoría ordenadas ... Ahora incluye el enfoque de pandas de @firelynx - lento, pero no horriblemente, y simple. Nota: el enfoque de clasificación / tee / zip es consistentemente más rápido en mi máquina para listas grandes en su mayoría ordenadas, moooeeeep es más rápido para listas barajadas, pero su millaje puede variar.
Ventajas
Supuestos
La solución más rápida, 1 millón de entradas:
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
Enfoques probados
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
Los resultados para la prueba de 'todos los duplicados' fueron consistentes, encontrando "primero" duplicado y luego "todos" duplicados en esta matriz:
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
Cuando las listas se barajan primero, el precio del tipo se hace evidente: la eficiencia cae notablemente y el enfoque @moooeeeep domina, con enfoques set & dict que son similares pero de menor rendimiento:
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)
dar cuenta de eso. Además, tampoco puedo replicar sus resultados cuando ejecuto el script inalterado (un orden totalmente diferente), por lo que tal vez también dependa de la CPU.
Usando pandas:
>>> import pandas as pd
>>> a = [1, 2, 1, 3, 3, 3, 0]
>>> pd.Series(a)[pd.Series(a).duplicated()].values
array([1, 3, 3])
collections.Counter es nuevo en 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'
>>>
En una versión anterior, puede usar un dict convencional en su lugar:
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]
Aquí hay una solución ordenada y concisa:
for x in set(li):
li.remove(x)
li = list(set(li))
Sin convertir a la lista y probablemente la forma más simple sería algo como a continuación. Esto puede ser útil durante una entrevista cuando piden no usar sets
a=[1,2,3,3,3]
dup=[]
for each in a:
if each not in dup:
dup.append(each)
print(dup)
======= más para obtener 2 listas separadas de valores únicos y valores duplicados
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)
Haría esto con los pandas, porque los uso mucho
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()
Da
[3,6]
Probablemente no sea muy eficiente, pero seguro es menos código que muchas de las otras respuestas, así que pensé que contribuiría
pda = pd.Series(a)
print list(pda[pda.duplicated()])
El tercer ejemplo de la respuesta aceptada da una respuesta errónea y no intenta dar duplicados. Aquí está la versión correcta:
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
¿Qué tal si simplemente recorre cada elemento de la lista verificando el número de ocurrencias y luego agregándolos a un conjunto que luego imprimirá los duplicados? Espero que esto ayude a alguien por ahí.
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]
Podemos usar itertools.groupby
para encontrar todos los artículos que tienen dups:
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
El resultado será:
4
6
dupes = [x for x, y in groupby(sorted(myList)) if len(list(y)) > 1]
Creo que la forma más efectiva de encontrar duplicados en una lista es:
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]))
Utiliza Counter
todos los elementos y todos los elementos únicos. Restar el primero con el segundo dejará fuera solo los duplicados.
Un poco tarde, pero tal vez útil para algunos. Para una lista grande, encontré que esto funcionó para mí.
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]
Muestra solo y todos los duplicados y conserva el orden.
La forma muy simple y rápida de encontrar personas engañadas con una iteración en Python es:
testList = ['red', 'blue', 'red', 'green', 'blue', 'blue']
testListDict = {}
for item in testList:
try:
testListDict[item] += 1
except:
testListDict[item] = 1
print testListDict
La salida será la siguiente:
>>> print testListDict
{'blue': 3, 'green': 1, 'red': 2}
Esto y más en mi blog http://www.howtoprogramwithpython.com
Estoy entrando mucho más tarde en esta discusión. Sin embargo, me gustaría tratar este problema con un revestimiento. Porque ese es el encanto de Python. si solo queremos obtener los duplicados en una lista separada (o cualquier colección), sugeriría hacer lo siguiente: digamos que tenemos una lista duplicada que podemos llamar como 'objetivo'
target=[1,2,3,4,4,4,3,5,6,8,4,3]
Ahora, si queremos obtener los duplicados, podemos usar el único revestimiento de la siguiente manera:
duplicates=dict(set((x,target.count(x)) for x in filter(lambda rec : target.count(rec)>1,target)))
Este código colocará los registros duplicados como clave y contará como valor en el diccionario 'duplicados'. El diccionario 'duplicado' tendrá el siguiente aspecto:
{3: 3, 4: 4} #it saying 3 is repeated 3 times and 4 is 4 times
Si solo desea todos los registros con duplicados solo en una lista, nuevamente es un código mucho más corto:
duplicates=filter(lambda rec : target.count(rec)>1,target)
La salida será:
[3, 4, 4, 4, 3, 4, 3]
Esto funciona perfectamente en las versiones de python 2.7.x +
Python 3.8 one-liner si no le importa escribir su propio algoritmo o usar bibliotecas:
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)
Imprime el artículo y cuenta:
[(1, 2), (2, 2), (5, 4)]
groupby
toma una función de agrupación para que pueda definir sus agrupaciones de diferentes maneras y devolver Tuple
campos adicionales según sea necesario.
groupby
es vago, por lo que no debería ser demasiado lento.
Algunas otras pruebas. Por supuesto que hacer ...
set([x for x in l if l.count(x) > 1])
... es muy costoso. Es aproximadamente 500 veces más rápido (la matriz más larga da mejores resultados) para usar el siguiente método final:
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 bucles, sin l.count()
operaciones muy costosas .
Aquí hay un código para comparar los métodos, por ejemplo. El código está abajo, aquí está la salida:
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
El código de prueba:
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()
Método 1:
list(set([val for idx, val in enumerate(input_list) if val in input_list[idx+1:]]))
Explicación: [val para idx, val en enumerate (input_list) si val en input_list [idx + 1:]] es una comprensión de la lista, que devuelve un elemento, si el mismo elemento está presente desde su posición actual, en la lista, el índice .
Ejemplo: input_list = [42,31,42,31,3,31,31,5,6,6,6,6,6,7,42]
comenzando con el primer elemento en la lista, 42, con el índice 0, verifica si el elemento 42 está presente en input_list [1:] (es decir, desde el índice 1 hasta el final de la lista) Porque 42 está presente en input_list [1:] , devolverá 42.
Luego va al siguiente elemento 31, con el índice 1, y verifica si el elemento 31 está presente en input_list [2:] (es decir, desde el índice 2 hasta el final de la lista), porque 31 está presente en input_list [2:], devolverá 31.
de manera similar, revisa todos los elementos de la lista y solo devolverá los elementos repetidos / duplicados en una lista.
Luego, debido a que tenemos duplicados, en una lista, necesitamos elegir uno de cada duplicado, es decir, eliminar duplicados entre duplicados, y para hacerlo, llamamos a un conjunto de nombres incorporado de Python (), y elimina los duplicados,
Luego nos queda un conjunto, pero no una lista, y por lo tanto, para convertir de un conjunto a una lista, usamos typecasting, list (), y eso convierte el conjunto de elementos en una lista.
Método 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
Explicación: Aquí creamos dos listas vacías, para empezar. Luego, siga recorriendo todos los elementos de la lista para ver si existe en temp_list (inicialmente vacío). Si no está allí en temp_list, entonces lo agregamos a temp_list, usando el método append .
Si ya existe en temp_list, significa que el elemento actual de la lista es un duplicado y, por lo tanto, debemos agregarlo a dupe_list usando el método 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]
Básicamente, elimina los duplicados convirtiéndolos en set ( clean_list
), luego itera raw_list
, mientras elimina cada uno item
en la lista limpia para que ocurra raw_list
. Si item
no se encuentra, ValueError
se captura la excepción generada y item
se agrega a la duplicated_items
lista.
Si se necesita el índice de elementos duplicados, solo enumerate
la lista y juegue con el índice. ( for index, item in enumerate(raw_list):
) que es más rápido y optimizado para listas grandes (como miles + de elementos)
uso del list.count()
método en la lista para descubrir los elementos duplicados de una lista dada
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)
Aquí hay muchas respuestas, pero creo que este es un enfoque relativamente fácil de leer y de entender:
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)
Notas:
Aquí hay un generador rápido que usa un dict para almacenar cada elemento como una clave con un valor booleano para verificar si el elemento duplicado ya ha sido entregado.
Para listas con todos los elementos que son tipos hashable:
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]
Para listas que pueden contener listas:
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]))
Al usar 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]
esta es la forma en que tuve que hacerlo porque me desafié a mí mismo a no usar otros métodos:
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
entonces su muestra funciona como:
>>>a = [1,2,3,3,3,4,5,6,6,7]
>>>dupList(a)
[1, 2, 3, 4, 5, 6, 7]
duplist = list(set(a))
.