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?
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]
[]
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))
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.
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)
" é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