2013-05-14 2 views
28

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

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

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

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

+2

ли операция * всегда * удалить элемент, или только иногда? Если вы всегда удаляете элемент, может быть проще просто очистить набор после завершения итерации. – Blckknght

ответ

14

Во-первых, используя набор, как рассказал нам Нулевой Пирей, вы можете

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] 
[] 
9

Это должно работать:

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

Или, если вам нужно удалить элементы условно:

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

myset = set(filter(test, myset)) 
+1

это хорошо работает, если я просто хочу удалить все из набора. В моем случае мне нужно овладеть каждым элементом и применить к нему функцию ** перед ** удалением из набора. – skyork

+0

@skyork удаляет элементы из итераций, когда вы перебираете их, - плохая идея (достаточно плохо, чтобы Python создавал исключение, если это сработало, это то, что вы делаете). Вам лучше построить новый набор, а затем выбросить старого. –

+2

«Удаление элементов из итераций по мере их перебора по ним - плохая идея (достаточно плохо, чтобы Python создавал исключение, если это сработало, это то, что вы делаете» - распространенное заблуждение, но неверное). Для некоторых iterables (hashtable- (примечание: не «плохая идея»), и Python сообщит вам об этом, когда вы попробуете. Для других повторений это совершенно правильно и, как только вы поймете, как это работает, предсказуемо. – kindall

4

Вернемся все четные числа при изменении текущего набора.

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

Вернется

>>> [2, 4] 

Если есть возможность использовать всегда использоватьlambda это сделает вашу жизнь проще.

+3

Я не знаю что 'lambda' всегда облегчает вашу жизнь ... На самом деле кажется, что обычно это не делает вашу жизнь проще. , , – mgilson

1

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

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

for member in myset: 
    myset.remove(member) 

(«член» лучший выбор имени переменной для множеств, «элемент» для списков)

Ах ... только что видели комментарий по доброй воле под ответом Zero P: очевидно, что я эксперт, где я болван, но я отправлю свой ответ в любом случае, просто чтобы привлечь внимание к точке ...

NB Zero P считает, что это утверждение в порядке с враждебностью ... но учитывая, что наборы, по дизайну, неупорядочены, я думаю, мы можем заключить, что ошибки параллелизма должны (и делать? в Python?) возникают только при удалении из n упорядоченная коллекция (т. list - и даже тогда вы можете использовать обратный индекс обратного индекса, чтобы избежать проблемы).

Было бы поэтому появляется, что отвращение к делеции-While-итерации этого дела суеверия и/или похмелья от негативного опыта от плохо реализованных структур на других языках.

Заключительная мысль: наборы и итерации не очень хорошо сочетаются друг с другом: поскольку набор неупорядочен, вы можете только когда-либо итерировать случайным образом по подмножеству всех членов (в частности, подмножество «все» или «сам», !). Наборы оптимизированы для тестов равенства и удаления дубликатов, и это отражает их предполагаемое использование. (? Идеальное решение)

Так эквивалентный бит кода к вышеупомянутому является:

while myset: 
    member = myset.pop() 
    # do something 
+3

Когда я использую первый метод, я получаю «RuntimeError: установка измененного размера во время итерации» в python2.7 и 3.5 (а второй метод опустошает набор). – Mark

2

Другой способ может быть:

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) 
+0

Я не понимаю, как это пытается ответить на вопрос? – Carpetsmoker

+0

Теперь имеет смысл, возможно: D..Lost соединение при редактировании. –

+0

Это в основном то же самое, что предложение @ zero-piraeus только медленнее. – SleepProgger

Смежные вопросы