supprimer des éléments d'un ensemble tout en itérant dessus

J'ai un set myset, et j'ai une fonction qui parcourt à effectuer une opération sur ses éléments, et cette opération en fin de compte supprime l'élément de l'ensemble.

Évidemment, je ne peux pas le faire tout en itérant sur l'ensemble d'origine. Je peux cependant faire ceci:

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

Y a-t-il un meilleur moyen?

29
demandé sur skyork 2013-05-14 23:30:09

5 réponses

Tout d'abord, en utilisant un ensemble, comme zéro Pirée nous l'a dit, vous pouvez

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

J'ai ajouté une méthode d'impression donnant ces sorties

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

Si vous voulez vous en tenir à votre choix pour une liste, je vous suggère de copier en profondeur la liste en utilisant une compréhension de liste, et de faire une boucle sur la copie, tout en supprimant les éléments de la liste d'origine. Dans mon exemple, je fais diminuer la longueur de la liste d'origine à chaque boucle.

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

Donne

>>> 
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
16
répondu octoback 2015-03-23 17:30:59

Cela devrait fonctionner:

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

Ou, si vous devez supprimer des éléments conditionnellement:

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

myset = set(filter(test, myset))
10
répondu Zero Piraeus 2013-05-14 20:04:52

Retournons tous les nombres pairs lors de la modification de l'ensemble actuel.

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

Retourne

>>> [2, 4]

S'il y a une opportunité utiliser toujours utiliser lambda cela vous rendra la vie plus facile.

4
répondu That_User 2013-05-15 10:24:22

Une autre façon pourrait être:

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
répondu Sanjeev Kumar 2016-08-09 18:26:57

" évidemment, je ne peux pas le faire tout en itérant sur l'ensemble d'origine."

Je ne suis pas sûr que ce soit vrai... Je m'attendais à des erreurs de "concurrence" quand je l'ai essayé mais ne semble pas en avoir. Pour mémoire, le code que j'utilise ressemble à ceci:

for member in myset:
    myset.remove( member )

("membre" est un meilleur choix de nom de variable pour les ensembles; "élément" pour les listes)

Ah... je viens de voir le commentaire de kindall sous la réponse de Zero P: évidemment, kindall est un expert où je suis un bourdon, mais je posterai mon répondez de toute façon juste pour attirer l'attention sur le point...

NB Zero P considère l'affirmation de kindall que c'est OK avec l'hostilité... mais étant donné que les ensembles sont, par conception, non ordonnés, je pense que nous pouvons conclure que les erreurs de concurrence devraient (et faire? en Python?) rogner uniquement lors de la suppression d'une collection ordonnée (c'est - à-dire liste-et même alors, vous pouvez utiliser un compte à rebours d'index inverse pour éviter le problème).

Il serait donc apparaissent que de l'aversion à l' la suppression-tout-itération est une question de superstition et/ou de gueule de bois de mauvaises expériences de structures mal implémentées dans d'autres langues.

Pensée finale: les ensembles et les itérations ne vont pas vraiment très bien ensemble: puisqu'un ensemble n'est pas ordonné, vous ne pourriez jamais itérer de manière aléatoire que sur un sous-ensemble de tous les membres (en particulier le sous-ensemble 'all' ou 'lui-même'!). Les ensembles sont optimisés pour les tests d'égalité et la suppression des doublons, ce qui reflète leur utilisation prévue.

Donc un bit de code équivalent à ce qui précède (la solution idéale?) est:

while myset:
    member = myset.pop()
    # do something
0
répondu mike rodent 2017-11-22 13:57:45