eliminar elementos de un conjunto mientras se itera sobre él


Tengo un conjunto myset, y tengo una función que itera sobre él para realizar alguna operación en sus elementos y esta operación finalmente elimina el elemento del conjunto.

Obviamente, no puedo hacerlo mientras sigo iterando sobre el conjunto original. Puedo, sin embargo, hacer esto:

mylist = list(myset)
for item in mylist:
    # do sth

¿hay alguna manera mejor?

Author: skyork, 2013-05-14

5 answers

Primero, usando un conjunto, como nos dijo Zero Piraeus, puedes

myset = set([3,4,5,6,2])
while myset:
    myset.pop()
    print myset

He añadido un método de impresión que da estas salidas

>>> 
set([3, 4, 5, 6])
set([4, 5, 6])
set([5, 6])
set([6])
set([])

Si desea atenerse a su elección para una lista, le sugiero que copie profundamente la lista utilizando una comprensión de lista, y recorra la copia, mientras elimina elementos de la lista original. En mi ejemplo, hago que la longitud de la lista original disminuya en cada bucle.

l = list(myset)
l_copy = [x for x in l]
for k in l_copy:
    l = l[1:]
    print l

Da

>>> 
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
 16
Author: octoback,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-23 17:30:59

Esto debería funcionar:

while myset:
    item = myset.pop()
    # do something

O, si necesita eliminar elementos condicionalmente:

def test(item):
    return item != "foo"  # or whatever

myset = set(filter(test, myset))
 10
Author: Zero Piraeus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-14 20:04:52

Devolvamos todos los números pares mientras modificamos el conjunto actual.

myset = set(range(1,5))
myset = filter(lambda x:x%2==0, myset)
print myset

Volverá

>>> [2, 4]

Si hay oportunidad use siempre use lambda te hará la vida más fácil.

 4
Author: That_User,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-15 10:24:22

Otra forma podría ser :

s=set()
s.add(1)
s.add(2)
s.add(3)
s.add(4)
while len(s)>0:
    v=next(iter(s))
    s.remove(v)
 2
Author: Sanjeev Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-09 18:26:57

"Obviamente, no puedo hacerlo mientras sigo iterando sobre el conjunto original."

No estoy seguro de que eso sea cierto... Esperaba errores de "concurrencia" cuando lo intenté, pero no parece tener ninguno. Para el registro, el código que estoy usando se ve así:

for member in myset:
    myset.remove( member )

("miembro "es una mejor opción de nombre de variable para conjuntos;" elemento " para listas)

Ah... acabo de ver el comentario de kindall bajo la respuesta de Zero P: obviamente kindall es un experto donde soy un torpe, pero voy a publicar mi responda de todos modos solo para llamar la atención sobre el punto...

NB Zero P se refiere a la afirmación de kindall de que esto está bien con la hostilidad... pero dado que los conjuntos son, por diseño, desordenados, creo que podemos concluir que los errores de concurrencia deben (y hacer? en Python?) aparecer solo cuando se elimina de una colección ordenada (es decir, lista - e incluso entonces se podría utilizar una cuenta atrás de índice para evitar el problema).

Por lo tanto, seríaaparecer esa aversión a la eliminación mientras se itera es una cuestión de superstición y / o resaca de malas experiencias de estructuras mal implementadas en otros lenguajes.

Pensamiento final: los conjuntos y las iteraciones realmente no van juntos terriblemente bien: ya que un conjunto no está ordenado, solo podría estar iterando de manera aleatoria sobre un subconjunto de todos los miembros (específicamente el subconjunto 'todos' o 'sí mismo'!). Los conjuntos están optimizados para pruebas de igualdad y eliminación de duplicados, y esto refleja su uso previsto.

So un bit de código equivalente a lo anterior (¿la solución ideal?) is:

while myset:
    member = myset.pop()
    # do something
 0
Author: mike rodent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-22 13:57:45