2010-08-04 8 views
17

Si tengo dos conjuntos idénticos, lo que significa a == b me da True, ¿tendrán el mismo orden de iteración? Lo intenté, y funciona:Orden de iteración de conjuntos en Python

>>> foo = set("abc") 
>>> bar = set("abc") 
>>> zip(foo, bar) 
[('a', 'a'), ('c', 'c'), ('b', 'b')] 

Mi pregunta es, ¿tuve suerte o este comportamiento está garantizado?

+0

Si a es 'B' Creo que van a tener el mismo orden de iteración. Por otra parte, ese no es un punto muy sutil = p – katrielalex

Respuesta

21

No fue solo coincidencia que salieron iguales: la implementación es determinista, por lo que crear el mismo conjunto dos veces produce el mismo orden. Pero Python no garantiza eso.

Si crea el mismo conjunto de dos maneras diferentes:

n = set("abc") 
print n 

m = set("kabc") 
m.remove("k") 
print m 

... usted puede obtener diferentes pedidos:

set(['a', 'c', 'b']) 
set(['a', 'b', 'c']) 
+0

+1 contraejemplo más simple. – katrielalex

+0

Otro muy buen contraejemplo. ¡Gracias! –

+0

Tiene toda la razón: no fue una coincidencia. Por ejemplo, parece que si crea el mismo conjunto directamente sin eliminar nada, siempre obtendrá el mismo orden: Por ejemplo: set ("abbacca") da set ('a', 'c', 'b') también como conjunto ("bbabbca"). Este comportamiento no es estocástico y está vinculado a la implementación. Sería interesante mirar el código fuente de python :) (Pero en todos los casos sería definitivamente una mala idea confiar en él :)) – ThR37

4

Tuviste suerte, el pedido no está garantizado. Lo único que está garantizado es que los conjuntos tendrán los mismos elementos.

Si necesita algún tipo de previsibilidad, puede ordenarlos así: zip(sorted(foo), sorted(bar)).

0

Yo diría que tienes suerte. Sin embargo, también podría ser que, dado que los elementos en el conjunto eran los mismos, se almacenaron en el mismo orden. Este comportamiento no es algo en lo que quieras confiar.

4

No .:

>>> class MyStr(str): 
...  def __hash__(self): 
...    return 0 
... 
>>> a = MyStr("a") 
>>> b = MyStr("b") 
>>> c = MyStr("c") 
>>> foo = { a, b, c } 
>>> foo 
{'c', 'b', 'a'} 
>>> bar = { b, a, c } 
>>> foo is bar 
False 
>>> foo == bar 
True 
>>> list(zip(foo, bar)) 
[('c', 'c'), ('b', 'a'), ('a', 'b')] 

P. S. No tengo idea si la anulación __hash__ es necesaria. Solo intenté algo que pensé que rompería esto, y lo hizo.

+0

Bueno, sin embargo, demuestra el punto. Si hay colisiones hash, la orden probablemente dependería de algo más allá de mi control. ¡Gracias! –

1

Sí, tenías suerte. Véase, por ejemplo:

import random 
r = [random.randint(1,10000) for i in range(20)] 
foo = set(r) 
r.sort(key=lambda _: random.randint(1,10000)) 
bar = set(r) 
print foo==bar 
print zip(foo, bar) 

Lo que me dio el resultado:

True 
[(3234, 3234), (9393, 9393), (9361, 1097), (1097, 5994), (5994, 2044), (1614, 1614), (6074, 4377), (4377, 9361), (5202, 5202), (2355, 2355), (1012, 1012), (7349, 7349), (6198, 6198), (8489, 8489), (7929, 7929), (6556, 6074), (6971, 6971), (2044, 6556), (7133, 7133), (383, 383)] 
Cuestiones relacionadas