Подтвердить что ты не робот

Удалять элементы из набора во время итерации по нему

У меня есть набор myset, и у меня есть функция, которая выполняет итерацию над ней, чтобы выполнить некоторую операцию над ее элементами, и эта операция в конечном итоге удаляет элемент из набора.

Очевидно, я не могу сделать это, продолжая повторять исходный набор. Я могу, однако, сделать это:

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

Есть ли лучший способ?

4b9b3361

Ответ 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