Ditado Python como criar chave ou acrescentar um elemento à chave?

161

Eu tenho um dicionário vazio. Nome: dict_x é para ter chaves cujos valores são listas.

A partir de uma iteração separada, obtenho uma chave (ex:) key_123e um item (uma tupla) para colocar na lista do dict_xvalor de key_123.

Se essa chave já existir, desejo anexar este item. Se essa chave não existir, desejo criá-la com uma lista vazia e anexá-la ou apenas criá-la com uma tupla.

No futuro, quando essa chave surgir novamente, já que ela existe, quero que o valor seja acrescentado novamente.

Meu código consiste nisso:

Obter chave e valor.

Veja se a chave NOT existe dict_x.

e se não o criar: dict_x[key] == []

Mais tarde: dict_x[key].append(value)

É assim que se faz? Devo tentar usar try/exceptblocos?

Phil
fonte

Respostas:

253

Use dict.setdefault():

dic.setdefault(key,[]).append(value)

ajuda (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
Ashwini Chaudhary
fonte
4
Eu costumava fazer isso, dict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]mas essa resposta sugere uma maneira muito melhor. Na verdade ele fica set()como um argumento e permite que você use add()método ...
fatih_dur
66

Aqui estão as várias maneiras de fazer isso, para que você possa comparar a aparência e escolher o que mais gosta. Ordenei-os de uma maneira que considero mais "pitônica" e comentei os prós e contras que podem não ser óbvios à primeira vista:

Usando collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

Prós: Provavelmente, melhor desempenho. Contras: Não disponível no Python 2.4.x.

Usando dict().setdefault():

dict_x = {}

...

dict_x.setdefault(key, []).append(value)

Contras: criação ineficiente de list()s não utilizados .

Usando try ... except:

dict_x = {}

...

try:
    values = dict_x[key]
except KeyError:
    values = dict_x[key] = []
values.append(value)

Ou:

try:
    dict_x[key].append(value)
except KeyError:
    dict_x[key] = [value]
Antak
fonte
Olá, por que você acha que .setdefault cria dicionários desnecessários?
Phil
2
Eu não acho que .setdefault()cria dicionários desnecessários. Eu acho que estou criando lists desnecessários (ie []) no segundo argumento de .setdefault()que nunca é usado se keyjá existe. Eu poderia usar dict.setdefault()(para o benefício de um hash de chave eficiente) e usar uma variável para reutilizar lists não utilizados, mas isso adiciona mais algumas linhas de código.
antak
1
IIRC, no Python, uma lista vazia em uma igualdade é considerada uma constante no nível do bytecode, mas isso precisa de alguma confirmação por um guru do bytecode (ou apenas use o módulo disas).
gaborous
Usando .setdefaultcria um regular dictonde chave ausente look-up irá resultar em um KeyErrorenquanto collections.defaultdict(list)cria uma dictonde pesquisas de chave ausentes irá inserir um vazio list- eu acho que você deve escolher com base no qual o comportamento que você quer
Chris_Rands
Eu tentei algo semelhante ao collections.defaultdict no meu próprio código e teve efeitos colaterais inesperados. Por exemplo, considere a seguinte troca IDLE: >>> list_dict = defaultdict (lista) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 Parece que quando o Python chama o valor padrão que adiciona a chave ao dicionário sem que você a defina ativamente, o que criará muitas listas vazias se o padrão for muito usado. Vou rolar minhas próprias funções de invólucro para o dicionário, ineficientes, mas espero mais previsíveis.
RDBury
26

Você pode usar um padrão para isso.

from collections import defaultdict
d = defaultdict(list)
d['key'].append('mykey')

Isso é um pouco mais eficiente do que setdefaultdesde que você não cria novas listas que não usa. Cada chamada para setdefaultcriará uma nova lista, mesmo que o item já exista no dicionário.

Nathan Villaescusa
fonte
14

Você pode usar o defaultdict em collections.

Um exemplo do doc:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
iMom0
fonte
0
dictionary['key'] = dictionary.get('key', []) + list_to_append
Tomas Silva Ebensperger
fonte
1
Você deve explicar a vantagem (muito pequena) que isso tem na presença de certas exceções; como apenas código, não está claro por que a resposta adicional é necessária.
Davis Herring
Oi, apenas uma alternativa sem importações adicionais. Isso pode ser feito claramente com uma declaração if. Estou apenas sugerindo uma alternativa usando o poder de .get () em vez de usar dict [].
Tomas Silva Ebensperger 08/07
As duas principais respostas mencionam duas maneiras diferentes, sem importações (embora não dict.get).
Davis Herring