Convertir una lista en un conjunto cambia el orden de los elementos

Recientemente noté que cuando estoy convirtiendo una list para set el orden de los elementos se cambia y se ordena por caracteres.

Considera 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é está pasando esto?
  2. ¿Cómo puedo realizar operaciones de configuración (especialmente Establecer diferencia) sin perder el pedido inicial?

  1. Un set es una estructura de datos desordenada.

  2. No utilice un set , sino collections.OrderedDict . 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 admita O (1) pruebas de membresía.

Edición : la respuesta anterior asume que usted desea poder realizar (establecer) operaciones de conjuntos en todas las colecciones que ocurren, en particular también en el resultado de una operación anterior de conjuntos. Si esto no es necesario, simplemente puede usar listas para algunas de las colecciones y conjuntos para otras, por ejemplo

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

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

En Python 3.6, set() ahora debería mantener el orden, pero hay otra solución para Python 2 y 3:

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

Respondiendo a su primera pregunta, un conjunto es una estructura de datos optimizada para las operaciones de conjunto. Como un conjunto matemático, no impone ni mantiene ningún orden particular de los elementos. El concepto abstracto de un conjunto no impone el orden, por lo que no se requiere que la implementación lo haga. Cuando crea un conjunto a partir de una lista, Python tiene la libertad de cambiar el orden de los elementos para las necesidades de la implementación interna que utiliza para un conjunto, que puede realizar operaciones de conjunto de manera eficiente.

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

Sin embargo, al usar una combinación de conjuntos y diccionarios, es posible que puedas lograr lo que quieras, intenta usar estos fragmentos de código:

 # 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 

Sobre la base de la respuesta de Sven, encontré el uso de colecciones. OrderedDict así me ayudó a lograr lo que desea y me permite agregar más elementos al 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 agregar elementos, pero aún así lo trata como un conjunto, simplemente puede hacer:

 z['nextitem']=None 

Y puede realizar una operación como z.keys () en el dict y obtener el conjunto:

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

Una implementación del concepto de puntaje más alto anterior que lo devuelve a una lista:

 def SetOfListInOrder(incominglist): from collections import OrderedDict outtemp = OrderedDict() for item in incominglist: outtemp[item] = None return(list(outtemp)) 

Probado (brevemente) en Python 3.6 y Python 2.7.

Aquí hay una manera fácil de hacerlo:

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