Python dict comment créer une clé ou ajouter un élément à la clé?

161

J'ai un dictionnaire vide. Nom: dict_x Il s'agit d'avoir des clés dont les valeurs sont des listes.

À partir d'une itération séparée, j'obtiens une clé (ex:) key_123et un élément (un tuple) à placer dans la liste de dict_xla valeur de key_123.

Si cette clé existe déjà, je souhaite ajouter cet élément. Si cette clé n'existe pas, je veux la créer avec une liste vide, puis y ajouter ou simplement la créer avec un tuple.

À l'avenir, lorsque cette clé apparaîtra de nouveau, puisqu'elle existe, je veux que la valeur soit à nouveau ajoutée.

Mon code se compose de ceci:

Obtenez la clé et la valeur.

Voir si la clé NOT existe dans dict_x.

et sinon créez-le: dict_x[key] == []

Ensuite: dict_x[key].append(value)

Est-ce la manière de procéder? Dois-je essayer d'utiliser des try/exceptblocs?

Phil
la source

Réponses:

254

Utilisez dict.setdefault():

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

aide (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
Ashwini Chaudhary
la source
4
J'avais l'habitude de faire cela dict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]mais cette réponse suggère une bien meilleure façon. En fait, il obtient set()comme argument et vous permet d'utiliser la add()méthode ...
fatih_dur
66

Voici les différentes façons de le faire afin que vous puissiez comparer son apparence et choisir ce que vous aimez. Je les ai commandés d'une manière que je pense être la plus "pythonique" , et j'ai commenté les avantages et les inconvénients qui pourraient ne pas être évidents à première vue:

Utilisation collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

Points positifs: Probablement les meilleures performances. Inconvénients: non disponible dans Python 2.4.x.

Utilisation dict().setdefault():

dict_x = {}

...

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

Inconvénients: création inefficace de list()s.

Utilisation 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
la source
Bonjour, pourquoi pensez-vous que .setdefault crée des dictionnaires inutiles?
Phil
2
Je ne pense pas que cela .setdefault()crée des dictionnaires inutiles. Je pense que je crée des lists inutiles (c'est-à-dire []) dans le deuxième argument de .setdefault()qui n'est jamais utilisé s'il keyexiste déjà. Je pourrais utiliser dict.setdefault()(pour un hachage efficace des clés), et utiliser une variable pour réutiliser les lists inutilisés mais cela ajoute quelques lignes de code supplémentaires.
antak
1
IIRC, en Python, une liste vide dans une égalité est considérée comme une constante au niveau du bytecode, mais cela nécessite une confirmation par un gourou du bytecode (ou utilisez simplement le module disas).
gaborous le
L'utilisation .setdefaultcrée une dictrecherche de clé régulière où la recherche de clé absente entraînera un KeyErrorcertain temps collections.defaultdict(list)crée une dictrecherche de clé où l'absence de clé insérera un vide list- je pense que vous devriez choisir en fonction du comportement que vous voulez
Chris_Rands
J'ai essayé quelque chose de similaire à collections.defaultdict dans mon propre code et cela a eu des effets secondaires inattendus. Par exemple, considérez l'échange IDLE suivant: >>> list_dict = defaultdict (list) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 Il apparaît que lorsque Python invoque la valeur par défaut, il ajoute la clé au dictionnaire sans que vous la définissiez activement, ce qui va créer beaucoup de listes vides si la valeur par défaut est beaucoup utilisée. Je vais lancer mes propres fonctions wrapper pour le dictionnaire, inefficaces mais, espérons-le, plus prévisibles.
RDBury
26

Vous pouvez utiliser un defaultdict pour cela.

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

C'est légèrement plus efficace que setdefaultpuisque vous ne finissez pas par créer de nouvelles listes que vous n'utilisez pas. Chaque appel à setdefaultva créer une nouvelle liste, même si l'élément existe déjà dans le dictionnaire.

Nathan Villaescusa
la source
14

Vous pouvez utiliser defaultdict dans collections.

Un exemple de 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
la source
0
dictionary['key'] = dictionary.get('key', []) + list_to_append
Tomas Silva Ebensperger
la source
1
Vous devez expliquer l'avantage (très mineur) que cela présente en présence de certaines exceptions; comme juste du code, on ne sait pas pourquoi la réponse supplémentaire est nécessaire.
Davis Herring
Salut, juste une alternative sans importations supplémentaires. Cela peut clairement être fait avec une instruction if. Je suggère juste une alternative utilisant la puissance de .get () au lieu d'utiliser dict [].
Tomas Silva Ebensperger le
Les deux premières réponses mentionnent deux manières différentes sans importations (mais non dict.get).
Davis Herring