2010-05-28 14 views
36

Considere una lista de Python my_list que contiene ['foo', 'foo', 'bar'].¿Cuál es la forma más limpia de hacer una clasificación más uniq en una lista de Python?

¿Cuál es la forma más pitonica de uniquify y ordenar una lista?
(piensa cat my_list | sort | uniq)

Así es como lo hago actualmente y mientras funciona estoy seguro de que hay mejores formas de hacerlo.

my_list = [] 
... 
my_list.append("foo") 
my_list.append("foo") 
my_list.append("bar") 
... 
my_list = set(my_list) 
my_list = list(my_list) 
my_list.sort() 
+0

Posible dupl icate de [¿Cómo eliminar duplicados de la lista de Python y mantener el orden?] (http://stackoverflow.com/questions/479897/how-to-remove-duplicates-from-python-list-and-keep-order) – sampablokuper

Respuesta

73
my_list = sorted(set(my_list)) 
+9

Nota que esto solo funciona para los tipos hashable, por lo que, por ejemplo, esto no funcionará en las listas. – taleinat

+0

Vale la pena mencionar que esto hace todo en la memoria mientras 'sort' (¿usualmente?) Sabe que persistirá en el disco. Si aplica esto a una gran cantidad de datos, debería fallar en 'MemoryError'. Buena respuesta, aunque :) –

+0

@ReutSharabani: No, lo diferente es que el método 'sort()' funciona en el lugar y por lo tanto no requiere asignación adicional. –

-4

no se puede decir que es la forma limpia de hacer eso, pero sólo por diversión:

my_list = [x for x in sorted(my_list) if not x in locals()["_[1]"]] 
+6

Esto es feo, mágico e innecesariamente cuadrático. –

+0

Claro, es solo por diversión, como noté. – andreypopp

5

La solución sencilla es proporcionada por Ignacio- sorted(set(foo)).

Si tiene datos únicos, existe la posibilidad razonable de que no solo desee hacer sorted(set(...)), sino almacenar un conjunto todo el tiempo y, ocasionalmente, extraer una versión ordenada de los valores. (En ese punto, comienza a sonar como el tipo de cosas para las que la gente suele usar una base de datos también).

Si tiene una lista ordenada y desea verificar la membresía en logarítmico y agregar un elemento en el peor de los casos, tiempo lineal , puede usar el bisect module.

Si desea mantener esta condición todo el tiempo y desea simplificar las cosas o hacer que algunas operaciones rindan mejor, puede considerar blist.sortedset.

+0

Considere [sortedcontainers] (http://www.grantjenks.com/docs/sortedcontainers/). [SortedSet] (http://www.grantjenks.com/docs/sortedcontainers/sortedset.html) en lugar de blist. Es [más rápido] (http://www.grantjenks.com/docs/sortedcontainers/performance.html) y pure-Python. – GrantJ

2

Otros han mencionado sorted (set (my_list)), que funciona para valores de hashable como cadenas, números y tuplas, pero no para tipos que no se pueden eliminar, como las listas.

Para obtener una lista ordenada de valores de cualquier tipo puede ordenar, sin duplicados:

from itertools import izip, islice 
def unique_sorted(values): 
    "Return a sorted list of the given values, without duplicates." 
    values = sorted(values) 
    if not values: 
     return [] 
    consecutive_pairs = izip(values, islice(values, 1, len(values))) 
    result = [a for (a, b) in consecutive_pairs if a != b] 
    result.append(values[-1]) 
    return result 

Esto se puede simplificar aún más el uso de los "pares" o "recetas" de la unique_justseen itertools documentation.

10
# Python ≥ 2.4 
# because of (generator expression) and itertools.groupby, sorted 

import itertools 

def sort_uniq(sequence): 
    return (x[0] for x in itertools.groupby(sorted(sequence))) 

más rápido:

import itertools, operator 
import sys 

if sys.hexversion < 0x03000000: 
    mapper= itertools.imap # 2.4 ≤ Python < 3 
else: 
    mapper= map # Python ≥ 3 

def sort_uniq(sequence): 
    return mapper(
     operator.itemgetter(0), 
     itertools.groupby(sorted(sequence))) 

Ambas versiones devuelven un generador, así que sería bueno para suministrar el resultado al tipo de lista:

sequence= list(sort_uniq(sequence)) 

Tenga en cuenta que esto funcionará con la no artículos hashable también:

>>> list(sort_uniq([[0],[1],[0]])) 
[[0], [1]] 
+1

Si está utilizando python3: Py3 map y en Py2 itertools.imap, haga exactamente lo mismo. (En Py3 iter (mapa (...)) es redundante.) –

+0

Esto es mucho mejor que la respuesta aceptada suponiendo que tiene una gran cantidad de datos. +1 –

+0

@TheDemz la respuesta es necesaria teniendo en cuenta que Python 3 es mucho más común ahora que entonces; Gracias – tzot

Cuestiones relacionadas