É legítimo excluir itens de um dicionário em Python enquanto itera sobre ele?
Por exemplo:
for k, v in mydict.iteritems():
if k == val:
del mydict[k]
A idéia é remover elementos que não atendem a uma determinada condição do dicionário, em vez de criar um novo dicionário que seja um subconjunto do que está sendo iterado.
Esta é uma boa solução? Existem maneiras mais elegantes / eficientes?
scripting
dictionary
python
Trilarion
fonte
fonte
Respostas:
EDITAR:
Esta resposta não funcionará para Python3 e fornecerá a
RuntimeError
.Isso acontece porque
mydict.keys()
retorna um iterador, não uma lista. Conforme indicado nos comentários, basta convertermydict.keys()
em uma lista porlist(mydict.keys())
e deve funcionar.Um teste simples no console mostra que você não pode modificar um dicionário enquanto itera sobre ele:
Conforme indicado na resposta de delnan, a exclusão de entradas causa problemas quando o iterador tenta passar para a próxima entrada. Em vez disso, use o
keys()
método para obter uma lista das chaves e trabalhar com isso:Se você precisar excluir com base no valor dos itens, use o
items()
método:fonte
for k, v in list(mydict.items()):
que funciona bem no Python 3. O mesmo parakeys()
se tornarlist(keys())
.RuntimeError: dictionary changed size during iteration
for k in list(mydict.keys()):
como python3 faz do método keys () um iterador e também não permite excluir itens de dict durante a iteração. Ao adicionar uma chamada de lista (), você transforma o iterador de chaves () em uma lista. Portanto, quando você está no corpo do loop for, não está mais iterando sobre o próprio dicionário.Você também pode fazer isso em duas etapas:
Minha abordagem favorita é geralmente fazer um novo ditado:
fonte
remove
mais da abordagem de loop.for k in [k for k in mydict if k == val]: del mydict[k]
Você não pode modificar uma coleção enquanto a itera. Essa maneira é loucura - principalmente, se você tivesse permissão para excluir e excluir o item atual, o iterador teria que seguir em frente (+1) e a próxima chamada
next
levaria você além disso (+2), para que você acabam pulando um elemento (o logo atrás do que você excluiu). Você tem duas opções:.keys()
et al para isso (no Python 3, passe o iterador resultante paralist
). Pode ser altamente desperdiçador em termos de espaço.mydict
normalmente, salvando as chaves para excluir em uma coleção separadato_delete
. Ao concluir a iteraçãomydict
, exclua todos os itensto_delete
demydict
. Economiza espaço (dependendo de quantas chaves foram excluídas e quantas permanecem) na primeira abordagem, mas também requer mais algumas linhas.fonte
You can't modify a collection while iterating it.
isso é correto para dictos e amigos, mas você pode modificar as listas durante a iteração:L = [1,2,None,4,5] <\n> for n,x in enumerate(L): <\n\t> if x is None: del L[n]
can't
é correto apenas para dict e amigos, enquanto deve sershouldn't
para listas.Itere uma cópia, como a retornada por
items()
:fonte
del v
diretamente, portanto, você fez uma cópia de cada v que você nunca vai usar e precisa acessar os itens por qualquer tecla.dict.keys()
é uma escolha melhor.v
como critério de exclusão.dict.items()
retorna um iterador em vez de uma cópia. Veja o comentário de Blair 's resposta , que (infelizmente) também assume Python 2 semântica.É mais limpo de usar
list(mydict)
:Isso corresponde a uma estrutura paralela para listas:
Ambos funcionam em python2 e python3.
fonte
Você pode usar uma compreensão de dicionário.
d = {k:d[k] for k in d if d[k] != val}
fonte
d
no lugar.Com python3, iterar em dic.keys () aumentará o erro de tamanho do dicionário. Você pode usar esta maneira alternativa:
Testado com python3, ele funciona bem e o erro " tamanho do dicionário alterado durante a iteração " não é gerado:
fonte
Você pode primeiro criar uma lista de chaves para excluir e, em seguida, iterar sobre essa lista, excluindo-as.
fonte
Existe uma maneira que pode ser adequada se os itens que você deseja excluir estiverem sempre no "início" da iteração de ditado
O "começo" é garantido apenas para ser consistente em determinadas versões / implementações do Python. Por exemplo, em Novidades no Python 3.7
Dessa forma, evita-se uma cópia do ditado que muitas das outras respostas sugerem, pelo menos no Python 3.
fonte
Eu tentei as soluções acima em Python3, mas esta parece ser a única que funciona para mim ao armazenar objetos em um ditado. Basicamente, você faz uma cópia do seu dict () e itera sobre ele enquanto exclui as entradas no seu dicionário original.
fonte