Compréhension du dictionnaire Python

386

Est-il possible de créer une compréhension de dictionnaire en Python (pour les clés)?

Sans compréhension de liste, vous pouvez utiliser quelque chose comme ceci:

l = []
for n in range(1, 11):
    l.append(n)

Nous pouvons raccourcir ce à une compréhension de la liste: l = [n for n in range(1, 11)].

Supposons toutefois que je souhaite définir les clés d'un dictionnaire sur la même valeur. Je peux faire:

d = {}
for n in range(1, 11):
     d[n] = True # same value for each

J'ai essayé ça:

d = {}
d[i for i in range(1, 11)] = True

Cependant, j'obtiens un SyntaxErrorsur le for.

De plus (je n'ai pas besoin de cette partie, mais je me demande simplement), pouvez-vous définir les clés d'un dictionnaire sur un tas de valeurs différentes, comme ceci:

d = {}
for n in range(1, 11):
    d[n] = n

Est-ce possible avec une compréhension du dictionnaire?

d = {}
d[i for i in range(1, 11)] = [x for x in range(1, 11)]

Cela soulève également un SyntaxErrorsur le for.

Rushy Panchal
la source
3
Pour les futurs lecteurs: les tableaux NumPy vous permettent de définir plusieurs éléments sur une seule valeur ou liste de valeurs, comme vous essayez de le faire. Bien que si vous n'avez pas encore de raison d'utiliser NumPy, cela ne vaut probablement pas le coup juste pour cette fonctionnalité.
David Z

Réponses:

520

Il existe des compréhensions de dictionnaire dans Python 2.7+ , mais elles ne fonctionnent pas exactement comme vous essayez. Comme une compréhension de liste, ils créent un nouveau dictionnaire; vous ne pouvez pas les utiliser pour ajouter des clés à un dictionnaire existant. En outre, vous devez spécifier les clés et les valeurs, bien que vous puissiez bien sûr spécifier une valeur fictive si vous le souhaitez.

>>> d = {n: n**2 for n in range(5)}
>>> print d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Si vous souhaitez les définir tous sur True:

>>> d = {n: True for n in range(5)}
>>> print d
{0: True, 1: True, 2: True, 3: True, 4: True}

Ce que vous semblez demander, c'est un moyen de définir plusieurs clés à la fois sur un dictionnaire existant. Il n'y a pas de raccourci direct pour cela. Vous pouvez soit boucler comme vous l'avez déjà montré, soit utiliser une compréhension du dictionnaire pour créer un nouveau dict avec les nouvelles valeurs, puis faire oldDict.update(newDict)pour fusionner les nouvelles valeurs dans l'ancien dict.

BrenBarn
la source
15
FWIW, dict.updatepeut également accepter un itérable de paires clé-valeur, tout comme le dictconstructeur
mgilson
6
Notez que si vous souhaitez créer un dictionnaire avec toutes les mêmes valeurs, utilisez dict.fromkeys(). Donc, pour définir toutes les valeurs sur True, utilisez dict.fromkeys(range(5), True). Attention, la valeur n'est pas copiée , vous pouvez donc éviter cela lorsque vous avez une valeur modifiable; il sera partagé entre toutes les clés.
Martijn Pieters
2
Remarque: les touches peuvent être le résultat d'une méthode aussi: { n*2 : n for n in range(3) } => {0: 0, 2: 1, 4: 2}. Les deux peuvent se faire dans la même expression: { n*2 : n*3 for n in range(3) } => { 0: 0, 2: 3, 4: 6 }.
Zaaier
151

Vous pouvez utiliser la dict.fromkeysméthode de classe ...

>>> dict.fromkeys(range(5), True)
{0: True, 1: True, 2: True, 3: True, 4: True}

C'est le moyen le plus rapide de créer un dictionnaire où toutes les clés correspondent à la même valeur.

Mais ne l' utilisez pas avec des objets mutables :

d = dict.fromkeys(range(5), [])
# {0: [], 1: [], 2: [], 3: [], 4: []}
d[1].append(2)
# {0: [2], 1: [2], 2: [2], 3: [2], 4: [2]} !!!

Si vous n'avez pas réellement besoin d'initialiser toutes les clés, un defaultdictpourrait également être utile:

from collections import defaultdict
d = defaultdict(True)

Pour répondre à la deuxième partie, une compréhension du dict est exactement ce dont vous avez besoin:

{k: k for k in range(10)}

Vous ne devriez probablement pas faire cela, mais vous pouvez également créer une sous-classe dictqui fonctionne un peu comme defaultdictsi vous remplacez __missing__:

>>> class KeyDict(dict):
...    def __missing__(self, key):
...       #self[key] = key  # Maybe add this also?
...       return key
... 
>>> d = KeyDict()
>>> d[1]
1
>>> d[2]
2
>>> d[3]
3
>>> print(d)
{}
mgilson
la source
Notez que dans le cas de d = defaultdict(lambda: True), le lambda n'est pas requis car True est (ou ne devrait pas) être mutable.
rhbvkleef
28
>>> {i:i for i in range(1, 11)}
{1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10}
NPE
la source
22

J'aime vraiment le commentaire @mgilson, car si vous avez deux itérables, l'un qui correspond aux clés et l'autre aux valeurs, vous pouvez également faire ce qui suit.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
d = dict(zip(keys, values))

donnant

d = {'a': 1, 'b': 2, 'c': 3}

ehontz
la source
4
Utilisation de la compréhension des {i:j for i in keys for j in values}
dictés
11

Utilisez dict () sur une liste de tuples, cette solution vous permettra d'avoir des valeurs arbitraires dans chaque liste, tant qu'elles sont de la même longueur

i_s = range(1, 11)
x_s = range(1, 11)
# x_s = range(11, 1, -1) # Also works
d = dict([(i_s[index], x_s[index], ) for index in range(len(i_s))])
Bryan
la source
12
En remarque, c'est la même chose qued = dict(zip(i_s,x_s))
mgilson
10

Considérez cet exemple de comptage de l'occurrence de mots dans une liste en utilisant la compréhension du dictionnaire

my_list = ['hello', 'hi', 'hello', 'today', 'morning', 'again', 'hello']
my_dict = {k:my_list.count(k) for k in my_list}
print(my_dict)

Et le résultat est

{'again': 1, 'hi': 1, 'hello': 3, 'today': 1, 'morning': 1}
adonese
la source
C'est intéressant, mais pas le plus efficace car vous compterez plusieurs fois des touches comme «bonjour»
FuriousGeorge
7

Le but principal d'une compréhension de liste est de créer une nouvelle liste basée sur une autre sans changer ou détruire la liste d'origine.

Au lieu d'écrire

    l = []
    for n in range(1, 11):
        l.append(n)

ou

    l = [n for n in range(1, 11)]

vous ne devez écrire que

    l = range(1, 11)

Dans les deux blocs de code supérieurs, vous créez une nouvelle liste, parcourez-la et retournez simplement chaque élément. C'est juste un moyen coûteux de créer une copie de liste.

Pour obtenir un nouveau dictionnaire avec toutes les clés définies sur la même valeur en fonction d'un autre dict, procédez comme suit:

    old_dict = {'a': 1, 'c': 3, 'b': 2}
    new_dict = { key:'your value here' for key in old_dict.keys()}

Vous recevez une erreur de syntaxe car lorsque vous écrivez

    d = {}
    d[i for i in range(1, 11)] = True

vous dites essentiellement: "Définir ma clé 'i pour i dans la plage (1, 11)' sur True" et "i pour i dans la plage (1, 11)" n'est pas une clé valide, c'est juste une erreur de syntaxe. Si dict les listes prises en charge comme clés, vous feriez quelque chose comme

    d[[i for i in range(1, 11)]] = True

et pas

    d[i for i in range(1, 11)] = True

mais les listes ne sont pas hachables, vous ne pouvez donc pas les utiliser comme clés dict.

Bonifacio2
la source
-3

vous ne pouvez pas hacher une liste comme ça. essayez ceci à la place, il utilise des tuples

d[tuple([i for i in range(1,11)])] = True
Aditya Sihag
la source