Является ли законным удаление элементов из словаря в Python при его повторении?
Например:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
Идея состоит в том, чтобы удалить элементы, которые не удовлетворяют определенному условию, из словаря, вместо того, чтобы создавать новый словарь, который является подмножеством повторяемого итератора.
Это хорошее решение? Есть ли более элегантные / эффективные способы?
scripting
dictionary
python
Trilarion
источник
источник
Ответы:
РЕДАКТИРОВАТЬ:
Этот ответ не будет работать для Python3 и даст
RuntimeError
.Это происходит потому, что
mydict.keys()
возвращает итератор, а не список. Как указано в комментариях, просто преобразуйтеmydict.keys()
в список,list(mydict.keys())
и это должно работать.Простой тест в консоли показывает, что вы не можете изменять словарь во время итерации по нему:
Как указано в ответе Делнана, удаление записей вызывает проблемы, когда итератор пытается перейти к следующей записи. Вместо этого используйте
keys()
метод, чтобы получить список ключей и работать с ним:Если вам нужно удалить на основе значения элементов, используйте
items()
вместо этого метод:источник
for k, v in list(mydict.items()):
который отлично работает в Python 3. То же самое дляkeys()
становленияlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
как python3 делает метод keys () итератором, а также запрещает удаление элементов dict во время итерации. Добавляя вызов list (), вы превращаете итератор keys () в список. Поэтому, когда вы находитесь в теле цикла for, вы больше не выполняете итерацию по самому словарю.Вы также можете сделать это в два этапа:
Мой любимый подход, как правило, просто сделать новый диктат:
источник
remove
циклический подход.for k in [k for k in mydict if k == val]: del mydict[k]
Вы не можете изменить коллекцию во время итерации. В этом и заключается безумие - особенно, если вам разрешат удалить и удалить текущий элемент, итератор должен будет двигаться дальше (+1), а следующий вызов, который
next
приведет вас к этому (+2), так что вы в конечном итоге пропускаем один элемент (тот, что сразу за тем, который вы удалили). У вас есть два варианта:.keys()
et al для этого (в Python 3 передать полученный итераторlist
). Может быть очень расточительно в отношении пространства, хотя.mydict
как обычно, сохраняя ключи для удаления в отдельной коллекцииto_delete
. Когда вы закончите итерациюmydict
, удалите все элементыto_delete
изmydict
. Сохраняет некоторое (в зависимости от того, сколько ключей удалено и сколько осталось) места по первому подходу, но также требуется еще несколько строк.источник
You can't modify a collection while iterating it.
это правильно для диктовок и друзей, но вы можете изменять списки во время итерации:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
это верно только для dict и друзей, в то время как это должно бытьshouldn't
для списков.Вместо этого переберите копию, например, возвращенную
items()
:источник
del v
напрямую, поэтому вы сделали копию каждого v, который вы никогда не собираетесь использовать, и вам все равно придется обращаться к элементам по ключу.dict.keys()
это лучший выбор.v
в качестве критерия для удаления.dict.items()
возвращает итератор, а не копию. Смотрите комментарий для Блэра «S ответа , который ( к сожалению) также принимает на себя Python 2 семантику.Это самый чистый для использования
list(mydict)
:Это соответствует параллельной структуре для списков:
Оба работают в python2 и python3.
источник
Вы можете использовать словарь понимания.
d = {k:d[k] for k in d if d[k] != val}
источник
d
на месте.При использовании python3 итерирование в dic.keys () вызовет ошибку размера словаря. Вы можете использовать этот альтернативный способ:
Протестировано с python3, работает нормально, и ошибка " словарь изменился в размерах во время итерации " не возникает:
источник
Вы можете сначала создать список ключей для удаления, а затем выполнить итерацию по этому списку, удалив их.
источник
Существует способ, который может подойти, если элементы, которые вы хотите удалить, всегда находятся в «начале» итерации dict.
«Начало» гарантированно будет согласованным только для определенных версий / реализаций Python. Например, из Что нового в Python 3.7
Таким образом, вы избегаете копии указания, которое предлагают многие другие ответы, по крайней мере, в Python 3.
источник
Я попробовал вышеупомянутые решения в Python3, но это, кажется, единственное, что работает для меня при хранении объектов в dict. По сути, вы делаете копию вашего dict () и перебираете его, удаляя записи в исходном словаре.
источник