2009-08-16 16 views

Respuesta

6

Ésta es otra manera orientada diccionario:

l = [0, 1, 1, 2, 2] 
d = {} 
for i in l: d[i] = d.has_key(i) 

[k for k in d.keys() if not d[k]] 
+0

+1 Muy bueno, no recoge un poco más de información de la que necesita para resolver la tarea. Sin embargo, puedes deshacerte de '.keys()'. –

+0

Sí, .keys() es totalmente opcional, pero un poco más fácil de leer. – mhawke

+0

buen pensamiento porque no tiene información innecesaria como la de Alex, aunque es esencialmente el mismo concepto, y no funcionará en elementos que no son aptos para el uso. –

12

Tendrá dos bucles (o equivalentemente un bucle y una listcomp, como a continuación), pero no los jerarquizados:

import collections 
d = collections.defaultdict(int) 
for x in L: d[x] += 1 
L[:] = [x for x in L if d[x] == 1] 

Esta solución supone que los elementos de la lista son hashable, es decir, que se pueden usar como índices en dicts, miembros de conjuntos, etc.

El OP indica que se preocupan por la IDENTIDAD del objeto y no por el VALOR (por ejemplo, dos sublistas con valor de [1,2,3 que son iguales pero pueden no ser idénticas no lo serían) ser considerado duplicado). Si ese es realmente el caso, entonces este código se puede utilizar, basta con sustituir d[x] con d[id(x)] en ambas ocurrencias y funcionará para cualquier tipo de objetos en la lista L.

objetos mutables (listas, Dicts, juegos, ...) son típicamente no es lavable y, por lo tanto, no se puede usar de esa manera. Los objetos definidos por el usuario son por defecto hashable (con hash(x) == id(x)) a menos que su clase defina métodos especiales de comparación (__eq__, __cmp__, ...) en cuyo caso son controlables si y solo si su clase también define un método __hash__.

Si los artículos lista L's no se hashable, pero son comparable para la desigualdad (y por lo tanto se puede ordenar), y que no se preocupan por su orden en la lista, puede realizar la tarea en el tiempo O(N log N) por primera clasificación de la enumere y luego aplique itertools.groupby (casi pero no del todo como se sugirió otra respuesta).

Otros enfoques, de rendimiento gradualmente decreciente y creciente generalidad, pueden tratarse con clasificaciones inigualables cuando CUESTE el orden original de la lista (haga una copia ordenada y en un segundo ciclo revise las repeticiones con la ayuda de bisect - - también O (N log N) pero un poco más lento), y con objetos cuya única propiedad aplicable es que son comparables por igualdad (no hay forma de evitar el temido rendimiento O (N ** 2) en ese caso máximo general) .

Si el PO puede aclarar qué caso se aplica a su problema específico voy a estar encantados de ayudarle (y, en particular, si los objetos en su son se hashable, el código Ya he dado más arriba debería ser suficiente ;-) .

+0

No, no necesito hash, creo que es solo la duplicación de objetos que quería eliminar. (Todavía estoy pensando en C, pero lo que quería decir era que por encima de los punteros a los objetos serán los mismos de modo que no es necesario para discutir - es que la tierra válido en Python?) –

+0

¿Por qué escribió "L [:] = list (set (L)) "en lugar de la más obvia (para mí)" L = list (set (L)) "? Parecen hacer lo mismo cuando los pruebo en el intérprete. ¿Hay algún matiz que me falta? ¡Gracias! – samtregar

+1

La segunda solución no parece hacer lo correcto: elimina los duplicados, pero el problema era eliminar todos los elementos que están duplicados. –

9
[x for x in the_list if the_list.count(x)==1] 

Aunque eso sigue siendo un bucle anidado detrás de las escenas.

+0

Sí, O (N ** 2) (mientras que el enfoque no anidado que muestro es O (N)). –

+0

Creo que prefiero la solución de Alex, ya que solo repite la lista dos veces, su solución es n^2. –

+0

WOW. ¡Realmente necesito irme y leer acerca de la comprensión de la lista! Todavía estoy tratando de descubrir exactamente qué está sucediendo arriba. Pero gracias mucho sepp y Alex. –

4
>>> l = [0,1,1,2,2] 
>>> [x for x in l if l.count(x) is 1] 
[0] 
+0

¿Hay alguna ventaja de usar 'is' over' == '? Sé que 1 es un número lo suficientemente pequeño para que esto funcione, pero ¿'es 'realmente más rápido cuando se comparan enteros? – Markus

+1

No debe usar 'is' con números, solo funciona porque cpython optimiza algunas constantes de uso frecuente (como pequeñas (<255) entradas, 1.0, 0.0, tuplas/conjuntos vacíos, etc.) y las trata como singletons ... pero eso no es parte del lenguaje * python *. –

+0

Do ** not ** use 'is' cuando se prueba la igualdad de valores. Esta solución es un enfoque de complejidad O (N ** 2) ya que 'list.count()' realiza un escaneo completo de la lista cada vez que lo llama, y ​​lo llama N veces. –

3
l = [0,1,2,1,2] 
def justonce(l): 
    once = set() 
    more = set() 
    for x in l: 
     if x not in more: 
      if x in once: 
       more.add(x) 
       once.remove(x) 
      else: 
       once.add(x) 
    return once 

print justonce(l) 
+0

Convertir de nuevo a una lista sería agradable. – nilamo

+0

Esto no conserva el orden como lo hace Alex. –

4

En el mismo espíritu que la solución de Alex puede utilizar un/Counter conjunto múltiple (construido en 2.7, receta compatibles entre 2.5 y superiores) para hacer la misma cosa:

In [1]: from counter import Counter 

In [2]: L = [0, 1, 1, 2, 2] 

In [3]: multiset = Counter(L) 

In [4]: [x for x in L if multiset[x] == 1] 
Out[4]: [0] 
1

creo que los tiempos actuales son bastante interesante:

Alex' respuesta:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import collections" "d = collections.defaultdict(int)" "for x in l: d[x] += 1" "l[:] = [x for x in l if d[x] == 1]" 
1000 loops, best of 3: 370 usec per loop 

Mina:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "once = set()" "more = set()" "for x in l:" " if x not in more:" " if x in once:" " more.add(x)" " once.remove(x)" " else:" " once.add(x)" 
1000 loops, best of 3: 275 usec per loop 
O

de sepp2k (n ** 2) versión, para demostrar por qué compexity importa ;-)

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "[x for x in l if l.count(x)==1]" 
100 loops, best of 3: 16 msec per loop 

+ de Roberto ordenados:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3); import itertools" "[elem[0] for elem in itertools.groupby(sorted(l)) if elem[1].next()== 0]" 
1000 loops, best of 3: 316 usec per loop 

mhawke de:

python -m timeit -s "l = range(1,1000,2) + range(1,1000,3)" "d = {}" "for i in l: d[i] = d.has_key(i)" "[k for k in d.keys() if not d[k]]" 
1000 loops, best of 3: 251 usec per loop 

me gusta el pasado, inteligente y rápido ;-)

1
>>> l = [0,1,1,2,2] 
>>> [x for x in l if l.count(x) == 1] 
[0] 
Cuestiones relacionadas