2012-03-20 34 views
42

Recientemente noté que cuando estoy convirtiendo la lista para establecer el orden o los elementos se cambia y se ordena por carácter.Establecer el orden de los elementos de los cambios?

Considere este ejemplo:

x=[1,2,20,6,210] 
print x 
# [1, 2, 20, 6, 210] # the order is same as initial order 

set(x) 
# set([1, 2, 20, 210, 6]) # in the set(x) output order is sorted 

Mis preguntas son -

  1. Por qué sucede esto?
  2. ¿Cómo puedo establecer operaciones (especialmente Establecer diferencia) sin perder el orden inicial?
+5

¿Por qué no quiere perder el pedido inicial, especialmente si está realizando operaciones de configuración? "orden" es un concepto sin sentido para conjuntos, no solo en Python, sino en matemáticas. –

+46

@KarlKnechtel - Sí "el orden es un concepto sin sentido para conjuntos ... en matemáticas" pero tengo problemas del mundo real :) –

Respuesta

50
  1. A set es una estructura de datos no ordenada.

  2. No utilice un set, sino más bien collections.OrderedDict:

    >>> a = collections.OrderedDict.fromkeys([1, 2, 20, 6, 210]) 
    >>> b = collections.OrderedDict.fromkeys([6, 20, 1]) 
    >>> collections.OrderedDict.fromkeys(x for x in a if x not in b) 
    OrderedDict([(2, None), (210, None)]) 
    

    Tenga en cuenta que el orden de b no importa, por lo que podría ser cualquier iterable, pero debe ser un iterable que soporta O (1) pruebas de membresía.

Editar: La respuesta anterior supone que usted quiere ser capaz de realizar las operaciones (ordenada) definidos en todas las colecciones que se producen, en particular también en el resultado de una operación anterior conjunto. Si esto no es necesario, puede simplemente usar listas para algunas de las colecciones y conjuntos para otras, p.

>>> a = [1, 2, 20, 6, 210] 
>>> b = set([6, 20, 1]) 
>>> [x for x in a if x not in b] 
[2, 210] 

Esta pierde el orden de b, no permite pruebas rápidas de miembros en a y el resultado. Los conjuntos permiten realizar pruebas de membresía rápidas y las listas mantienen el orden. Si necesita estas dos características en la misma colección, use collections.OrderedDict.

+0

Ninguno objeto cuesta 16 bytes. Si solo hay un OrderedSet predeterminado(). :( – Sean

13

Respondiendo a su primera pregunta, set es una estructura de datos optimizada para operaciones de conjunto, y como un conjunto matemático, no impone/mantiene ningún orden particular de los elementos. El concepto abstracto de conjunto no impone orden, tampoco lo hace la implementación. Cuando crea un conjunto a partir de una lista, python se toma la libertad de cambiar el orden de los elementos para las necesidades de la implementación interna que utiliza para un conjunto, que es capaz de realizar las operaciones establecidas de manera eficiente.

3

como se indica en otras respuestas, conjuntos son estructuras de datos (y los conceptos matemáticos) que no preservan el orden de los elementos -

Sin embargo, mediante el uso de una combinación de juegos y diccionarios, es posible que se puede lograr wathever usted quiere - intente utilizar estos fragmentos:

# save the element order in a dict: 
x_dict = dict(x,y for y, x in enumerate(my_list)) 
x_set = set(my_list) 
#perform desired set operations 
... 
#retrieve ordered list from the set: 
new_list = [None] * len(new_set) 
for element in new_set: 
    new_list[x_dict[element]] = element 
1

de construcción sobre la respuesta de Sven, encontré usando collections.OrderedDict al igual que me ha ayudado a lograr lo que quiere además me permite añadir más elementos a la dict:

import collections 

x=[1,2,20,6,210] 
z=collections.OrderedDict.fromkeys(x) 
z 
OrderedDict([(1, None), (2, None), (20, None), (6, None), (210, None)]) 

Si desea añadir elementos, pero todavía lo tratan como un conjunto que sólo puede hacer:

z['nextitem']=None 

Y se puede llevar a cabo una operación como z.llaves() en el dict y obtener el conjunto:

z.keys() 
[1, 2, 20, 6, 210] 
+0

tiene que hacer 'list (z.keys())' para obtener la salida de la lista. – jxn

+0

en Python 3, sí, no en Python 2, aunque debería haber especificado. – jimh

-5

Aquí está una manera fácil de hacerlo:

x=[1,2,20,6,210] 
print sorted(set(x)) 
+2

Esto no conserva el orden necesariamente –

+1

esta respuesta es correcta solo si la entrada está ordenada – msudder

10

En Python 3.6, set() ahora debe mantener el orden, pero hay otro solución para Python 2 y 3:

>>> x = [1, 2, 20, 6, 210] 
>>> sorted(set(x), key=x.index) 
[1, 2, 20, 6, 210] 
+8

Dos notas con respecto a la preservación de orden: solo a partir de Python 3.6, e incluso allí, se considera un detalle de implementación, así que no confíe en ello. Aparte de eso, su código es muy ineficaz porque cada vez que se llama a 'x.index', se realiza una búsqueda lineal. Si está bien con la complejidad cuadrática, no hay ninguna razón para usar un' conjunto 'en primer lugar. –

+9

@ThijsvanDien Esto está mal, ' set() 'no está ordenado en Python 3.6, ni siquiera como un detalle de implementación, estás pensando en' dict's –

+0

@Chris_Rands Me encuentro corregido; parecen estar ordenados, en lugar de mantener la inserción de rder. De cualquier forma: detalles de implementación. –

Cuestiones relacionadas