Удалять элементы из набора во время итерации по нему
У меня есть набор myset
, и у меня есть функция, которая выполняет итерацию над ней, чтобы выполнить некоторую операцию над ее элементами, и эта операция в конечном итоге удаляет элемент из набора.
Очевидно, я не могу сделать это, продолжая повторять исходный набор. Я могу, однако, сделать это:
mylist = list(myset)
for item in mylist:
# do sth
Есть ли лучший способ?
Ответы
Ответ 1
Сначала, используя набор, как сказал нам Zero Piraeus, вы можете
myset = set([3,4,5,6,2])
while myset:
myset.pop()
print myset
Я добавил метод печати, дающий эти выходы
>>>
set([3, 4, 5, 6])
set([4, 5, 6])
set([5, 6])
set([6])
set([])
Если вы хотите придерживаться своего выбора для списка, я предлагаю вам скопировать список, используя понимание списка, и перебрать копию, удалив элементы из исходного списка. В моем примере, я делаю длину исходного уменьшения списка в каждом цикле.
l = list(myset)
l_copy = [x for x in l]
for k in l_copy:
l = l[1:]
print l
дает
>>>
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
Ответ 2
Это должно работать:
while myset:
item = myset.pop()
# do something
Или, если вам нужно удалить элементы условно:
def test(item):
return item != "foo" # or whatever
myset = set(filter(test, myset))
Ответ 3
Пусть возвращают все четные числа при изменении текущего набора.
myset = set(range(1,5))
myset = filter(lambda x:x%2==0, myset)
print myset
Вернет
>>> [2, 4]
Если есть возможность использовать всегда использовать lambda
, это облегчит вам жизнь.
Ответ 4
Другой способ:
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)
Ответ 5
"Очевидно, что я не могу этого сделать, продолжая повторять исходный набор".
Я не уверен, что это правда... Я ожидал ошибок "concurrency", когда я его пробовал, но, похоже, не получил. Для записи код, который я использую, выглядит следующим образом:
for member in myset:
myset.remove( member )
( "член" - лучший выбор имени переменной для наборов, "элемент" для списков)
А... просто посмотрел комментарий по добрым словам под Zero P ответ: очевидно, любезно эксперт, где я болван, но я отправлю свой ответ в любом случае, просто чтобы привлечь внимание к точке...
NB Zero P рассматривает доброе утверждение о том, что это нормально с враждебностью... но учитывая, что наборы по дизайну неупорядочены, я думаю, мы можем заключить, что ошибки concurrency должны (и делать? в Python?) только при удалении из упорядоченной коллекции (т.е. списка - и даже тогда вы можете использовать обратный индекс обратного отсчета, чтобы избежать проблемы).
Таким образом, появится, что отвращение к удалению-итерации является вопросом суеверия и/или похмелья от плохого опыта от плохо реализованных структур на других языках.
Заключительная мысль: наборы и итерации не очень хорошо сочетаются друг с другом: поскольку набор неупорядочен, вы можете только когда-либо повторяться случайным образом над подмножеством всех членов (в частности, подмножество "все" или "сам"!). Наборы оптимизированы для тестов равенства и удаления дубликатов, и это отражает их предполагаемое использование.
Итак, эквивалентный бит кода выше (идеальное решение?):
while myset:
member = myset.pop()
# do something