2009-10-11 8 views
20

Esto es realmente una extensión de esta pregunta. Las respuestas de esa pregunta no mantuvieron el "orden" de la lista después de eliminar los duplicados. How to remove these duplicates in a list (python)Eliminar duplicados en una lista mientras se mantiene su orden (Python)

biglist = 

[ 

    {'title':'U2 Band','link':'u2.com'}, 
    {'title':'Live Concert by U2','link':'u2.com'}, 
    {'title':'ABC Station','link':'abc.com'} 

] 

En este caso, el segundo elemento debe ser eliminado porque un elemento previo "u2.com" ya existe. Sin embargo, la orden debe mantenerse.

Respuesta

23

Mi respuesta a su otra pregunta, que ignora por completo !, muestra se equivoca al afirmar que

las respuestas de la pregunta no lo hicieron mantener el "orden"

  • mi respuesta hizo mantener el orden, y claramente dijo lo hizo. Aquí está otra vez, con énfasis añadido para ver si sólo se puede seguir ignorando que ...:

Probablemente el método más rápido, para obtener una lista muy grande, si desea conservar el orden exacto de los artículos que permanecen, es el siguiente ...:

biglist = [ 
    {'title':'U2 Band','link':'u2.com'}, 
    {'title':'ABC Station','link':'abc.com'}, 
    {'title':'Live Concert by U2','link':'u2.com'} 
] 

known_links = set() 
newlist = [] 

for d in biglist: 
    link = d['link'] 
    if link in known_links: continue 
    newlist.append(d) 
    known_links.add(link) 

biglist[:] = newlist 
+3

Hola, Alex, por curiosidad, ¿por qué pones el [:] en el lado izquierdo de la tarea? Usualmente lo he visto en el RHS. ¿Es solo preferencia personal? Mirándolo al principio, ni siquiera estaba seguro de lo que haría, jaja. – xitrium

+2

@xitrium Al usar '[:]' a la izquierda se reemplazaron todos los elementos de la lista, en lugar de la lista en sí. Podría tener un efecto, por ej. si haces esto dentro de una función con una lista que se transfiere: si * cambias * la lista se cambia fuera de la función, si * la reemplazas * entonces la lista externa no se ve afectada). En este caso particular, no hay ningún efecto observable que pueda ver. – Mark

0

Una manera muy fácil de hacer esto es:

def uniq(a): 
    if len(a) == 0: 
     return [] 
    else: 
     return [a[0]] + uniq([x for x in a if x != a[0]]) 

Esta no es la forma más eficiente, debido a que:

  • que busca a través de toda la lista de todos los elementos de la lista, por lo es O (n^2)
  • es recursiva de modo utiliza una profundidad de pila igual a la longitud de la lista

Sin embargo, para usos simples (no más de unos pocos cientos de elementos, no el rendimiento crítico) es suficiente.

+0

¿Alguien puede venir con una forma que sea escalable? – TIMEX

+0

La respuesta de Kalmi apunta a una serie de buenas soluciones. –

3

Esta página discute los diferentes métodos y sus velocidades: http://www.peterbe.com/plog/uniqifiers-benchmark

El método recomendado *:

def f5(seq, idfun=None): 
    # order preserving 
    if idfun is None: 
     def idfun(x): return x 
    seen = {} 
    result = [] 
    for item in seq: 
     marker = idfun(item) 
     # in old Python versions: 
     # if seen.has_key(marker) 
     # but in new ones: 
     if marker in seen: continue 
     seen[marker] = 1 
     result.append(item) 
    return result 

f5(biglist,lambda x: x['link']) 

* por esa página

1
dups = {} 
newlist = [] 
for x in biglist: 
    if x['link'] not in dups: 
     newlist.append(x) 
     dups[x['link']] = None 

print newlist 

produce

[{'link': 'u2.com', 'title': 'U2 Band'}, {'link': 'abc.com', 'title': 'ABC Station'}] 

Tenga en cuenta que aquí utilicé un diccionario. Esto hace que la prueba not in dups sea mucho más eficiente que usar una lista.

+1

Se equivoca al comprobar que un dict es más rápido que en un conjunto (las listas son un asunto completamente diferente). –

+0

bien, arreglado, gracias. Supongo que el conjunto probablemente se implemente con un hash. – Peter

0

Creo que usar un conjunto debería ser bastante eficiente.

seen_links = set() 
for index in len(biglist): 
    link = biglist[index]['link'] 
    if link in seen_links: 
     del(biglist[index]) 
    seen_links.add(link) 

creo que esto debería venir en O (n log (n))

+2

de hecho es O (n^2) porque del en una lista es O (n) –

+0

Así es. ¡Gracias! – ABentSpoon

7

generadores son grandes.

def unique(seq): 
    seen = set() 
    for item in seq: 
     if item not in seen: 
      seen.add(item) 
      yield item 

biglist[:] = unique(biglist) 
+0

Esto es lo que necesitaba para mi problema. Sugiero que sea más genérico al agregar 'clave = elemento lambda: elemento' a la firma del método. Luego, use 'key (item)' para el conjunto. – Harvey

1
list = ['aaa','aba','aaa','aea','baa','aaa','aac','aaa',] 

uniq = [] 

for i in list: 
       if i not in uniq: 
        uniq.append(i) 

print list 

print uniq 

salida será:

[ 'aaa', 'aba', 'aaa', 'AEA', 'BAA', 'aaa', 'aac', 'aaa' ]

[ 'AAA', 'aba', 'aea', 'BAA', 'aac']

1

Esta es una manera elegante y compacto, con la lista de comprensión (pero no tan eficiente como con el diccionario) :

mylist = ['aaa','aba','aaa','aea','baa','aaa','aac','aaa',] 

[ v for (i,v) in enumerate(mylist) if v not in mylist[0:i] ] 

Y en el contexto de la respuesta:

[ v for (i,v) in enumerate(biglist) if v['link'] not in map(lambda d: d['link'], biglist[0:i]) ] 
29

conjunto de uso(), a continuación, volver a clasificar utilizando el índice de la lista original.

>>> mylist = ['c','a','a','b','a','b','c'] 
>>> sorted(set(mylist), key=lambda x: mylist.index(x)) 
['c', 'a', 'b'] 
+0

¡Esto es fantástico! Exactamente lo que estaba buscando. ¿Te importaría explicar cómo funciona? (con el uso de lambda, etc.) Gracias –

+1

Neat Python code. La desventaja es que causa un tipo extra, por lo tanto, un O (n * log (n)) innecesario (donde de lo contrario O (n) sería suficiente). – yprez

+0

puede ser ordenado, en cuanto a rendimiento, lejos de ser óptimo – Yerken

Cuestiones relacionadas