identificar - encontrar elementos repetidos en una lista python
Índice de elementos duplicados en una lista de Python (11)
Creo que encontré una solución simple después de mucha irritación:
if elem in string_list:
counter = 0
elem_pos = []
for i in string_list:
if i == elem:
elem_pos.append(counter)
counter = counter + 1
print(elem_pos)
Esto imprime una lista que le da los índices de un elemento específico ("elem")
¿Alguien sabe cómo puedo obtener la posición del índice de los elementos duplicados en una lista de Python? He intentado hacer esto y me sigue dando solo el índice de la primera aparición del ítem en la lista.
List = [''A'', ''B'', ''A'', ''C'', ''E'']
Quiero que me dé:
index 0: A
index 2: A
Desea pasar el segundo parámetro opcional para indexar, la ubicación donde desea que el índice comience a buscarse. Después de encontrar cada coincidencia, restablezca este parámetro a la ubicación justo después de la coincidencia que se encontró.
def list_duplicates_of(seq,item):
start_at = -1
locs = []
while True:
try:
loc = seq.index(item,start_at+1)
except ValueError:
break
else:
locs.append(loc)
start_at = loc
return locs
source = "ABABDBAAEDSBQEWBAFLSAFB"
print list_duplicates_of(source, ''B'')
Huellas dactilares:
[1, 3, 5, 11, 15, 22]
Puede encontrar todos los duplicados a la vez en un solo paso a través de la fuente, utilizando un valor predeterminado para mantener una lista de todas las ubicaciones vistas para cualquier artículo y devolver esos elementos que se vieron más de una vez.
from collections import defaultdict
def list_duplicates(seq):
tally = defaultdict(list)
for i,item in enumerate(seq):
tally[item].append(i)
return ((key,locs) for key,locs in tally.items()
if len(locs)>1)
for dup in sorted(list_duplicates(source)):
print dup
Huellas dactilares:
(''A'', [0, 2, 6, 7, 16, 20])
(''B'', [1, 3, 5, 11, 15, 22])
(''D'', [4, 9])
(''E'', [8, 13])
(''F'', [17, 21])
(''S'', [10, 19])
Si desea realizar pruebas repetidas para varias claves contra la misma fuente, puede usar functools.partial para crear una nueva variable de función, utilizando una lista de argumentos "parcialmente completa", es decir, especificando el seq, pero omitiendo el elemento para buscar para:
from functools import partial
dups_in_source = partial(list_duplicates_of, source)
for c in "ABDEFS":
print c, dups_in_source(c)
Huellas dactilares:
A [0, 2, 6, 7, 16, 20]
B [1, 3, 5, 11, 15, 22]
D [4, 9]
E [8, 13]
F [17, 21]
S [10, 19]
Guau, la respuesta de todos es muy larga. Simplemente utilicé un marco de datos de pandas , masking y la función duplicated ( keep=False
marca todos los duplicados como True
, no solo primero o último):
import pandas as pd
import numpy as np
np.random.seed(42) # make results reproducible
int_df = pd.DataFrame({''int_list'': np.random.randint(1, 20, size=10)})
dupes = int_df[''int_list''].duplicated(keep=False)
print(int_df[''int_list''][dupes].index)
Esto debería devolver Int64Index([0, 2, 3, 4, 6, 7, 9], dtype=''int64'')
.
Hice un punto de referencia de todas las soluciones sugeridas aquí y también agregué otra solución a este problema (que se describe al final de la respuesta).
Puntos de referencia
Primero, los puntos de referencia. Inicializo una lista de n
entradas aleatorias dentro de un rango [1, n/2]
y luego call timeit
sobre todos los algoritmos
Las soluciones de @ Paul McGuire y @ funcionan aproximadamente dos veces más rápido que el resto en la lista de 100 entradas:
Testing algorithm on the list of 100 items using 10000 loops
Algorithm: dupl_eat
Timing: 1.46247477189
####################
Algorithm: dupl_utdemir
Timing: 2.93324529055
####################
Algorithm: dupl_lthaulow
Timing: 3.89198786645
####################
Algorithm: dupl_pmcguire
Timing: 0.583058259784
####################
Algorithm: dupl_ivazques_abrams
Timing: 0.645062989076
####################
Algorithm: dupl_rbespal
Timing: 1.06523873786
####################
Si cambia el número de elementos a 1000, la diferencia se vuelve mucho más grande (por cierto, estaré feliz si alguien pudiera explicar por qué ):
Testing algorithm on the list of 1000 items using 1000 loops
Algorithm: dupl_eat
Timing: 5.46171654555
####################
Algorithm: dupl_utdemir
Timing: 25.5582547323
####################
Algorithm: dupl_lthaulow
Timing: 39.284285326
####################
Algorithm: dupl_pmcguire
Timing: 0.56558489513
####################
Algorithm: dupl_ivazques_abrams
Timing: 0.615980005148
####################
Algorithm: dupl_rbespal
Timing: 1.21610942322
####################
En las listas más grandes, la solución de @ Paul McGuire sigue siendo la más eficiente y mi algoritmo comienza a tener problemas.
Testing algorithm on the list of 1000000 items using 1 loops
Algorithm: dupl_pmcguire
Timing: 1.5019953958
####################
Algorithm: dupl_ivazques_abrams
Timing: 1.70856155898
####################
Algorithm: dupl_rbespal
Timing: 3.95820421595
####################
El código completo del benchmark está here
Otro algoritmo
Aquí está mi solución al mismo problema:
def dupl_rbespal(c):
alreadyAdded = False
dupl_c = dict()
sorted_ind_c = sorted(range(len(c)), key=lambda x: c[x]) # sort incoming list but save the indexes of sorted items
for i in xrange(len(c) - 1): # loop over indexes of sorted items
if c[sorted_ind_c[i]] == c[sorted_ind_c[i+1]]: # if two consecutive indexes point to the same value, add it to the duplicates
if not alreadyAdded:
dupl_c[c[sorted_ind_c[i]]] = [sorted_ind_c[i], sorted_ind_c[i+1]]
alreadyAdded = True
else:
dupl_c[c[sorted_ind_c[i]]].append( sorted_ind_c[i+1] )
else:
alreadyAdded = False
return dupl_c
Aunque no es lo mejor, me permitió generar una estructura un poco diferente para mi problema (necesitaba algo así como una lista vinculada de índices del mismo valor)
Hola chicos, lo hago simple:
i = [1,2,1,3]
k = 0
for ii in i:
if ii == 1 :
print ("index of 1 = ", k)
k = k+1
salida:
índice de 1 = 0
índice de 1 = 2
Mencionaré la forma más obvia de tratar con duplicados en las listas. En términos de complejidad, los diccionarios son el camino a seguir porque cada búsqueda es O (1). Puede ser más inteligente si solo está interesado en duplicados ...
my_list = [1,1,2,3,4,5,5]
my_dict = {}
for (ind,elem) in enumerate(my_list):
if elem in my_dict:
my_dict[elem].append(ind)
else:
my_dict.update({elem:[ind]})
for key,value in my_dict.iteritems():
if len(value) > 1:
print "key(%s) has indices (%s)" %(key,value)
que imprime lo siguiente:
key(1) has indices ([0, 1])
key(5) has indices ([5, 6])
Usando la nueva clase "Contador" en el módulo de colecciones, basado en la respuesta de lazyr:
>>> import collections
>>> def duplicates(n): #n="123123123"
... counter=collections.Counter(n) #{''1'': 3, ''3'': 3, ''2'': 3}
... dups=[i for i in counter if counter[i]!=1] #[''1'',''3'',''2'']
... result={}
... for item in dups:
... result[item]=[i for i,j in enumerate(n) if j==item]
... return result
...
>>> duplicates("123123123")
{''1'': [0, 3, 6], ''3'': [2, 5, 8], ''2'': [1, 4, 7]}
>>> def duplicates(lst, item):
... return [i for i, x in enumerate(lst) if x == item]
...
>>> duplicates(List, "A")
[0, 2]
Para obtener todos los duplicados, puede usar el siguiente método, pero no es muy eficiente. Si la eficiencia es importante, debes considerar la solución de Ignacio.
>>> dict((x, duplicates(List, x)) for x in set(List) if List.count(x) > 1)
{''A'': [0, 2]}
En cuanto a resolverlo usando el método de index
de list
lugar, ese método toma un segundo argumento opcional que indica por dónde empezar, por lo que podría llamarlo repetidamente con el índice anterior más 1.
>>> List.index("A")
0
>>> List.index("A", 1)
2
EDITAR Problema resuelto planteado en los comentarios.
dups = collections.defaultdict(list)
for i, e in enumerate(L):
dups[e].append(i)
for k, v in sorted(dups.iteritems()):
if len(v) >= 2:
print ''%s: %r'' % (k, v)
Y extrapolar desde allí.
from collections import Counter, defaultdict
def duplicates(lst):
cnt= Counter(lst)
return [key for key in cnt.keys() if cnt[key]> 1]
def duplicates_indices(lst):
dup, ind= duplicates(lst), defaultdict(list)
for i, v in enumerate(lst):
if v in dup: ind[v].append(i)
return ind
lst= [''a'', ''b'', ''a'', ''c'', ''b'', ''a'', ''e'']
print duplicates(lst) # [''a'', ''b'']
print duplicates_indices(lst) # ..., {''a'': [0, 2, 5], ''b'': [1, 4]})
Una implementación ligeramente más ortogonal (y por lo tanto más útil) sería:
from collections import Counter, defaultdict
def duplicates(lst):
cnt= Counter(lst)
return [key for key in cnt.keys() if cnt[key]> 1]
def indices(lst, items= None):
items, ind= set(lst) if items is None else items, defaultdict(list)
for i, v in enumerate(lst):
if v in items: ind[v].append(i)
return ind
lst= [''a'', ''b'', ''a'', ''c'', ''b'', ''a'', ''e'']
print indices(lst, duplicates(lst)) # ..., {''a'': [0, 2, 5], ''b'': [1, 4]})
string_list = [''A'', ''B'', ''C'', ''B'', ''D'', ''B'']
pos_list = []
for i in range(len(string_list)):
if string_list[i] = =''B'':
pos_list.append(i)
print pos_list