web-dev-qa-db-fra.com

Renommer une clé de dictionnaire

Existe-t-il un moyen de renommer une clé de dictionnaire sans réaffecter sa valeur à un nouveau nom ni supprimer l'ancienne clé de nom; et sans itérer via dict clé/valeur?

En cas de OrderedDict, faites la même chose, tout en conservant la position de cette clé.

319
rabin utam

Pour un dict régulier, vous pouvez utiliser:

mydict[new_key] = mydict.pop(old_key)

Pour un OrderedDict, je pense que vous devez en construire un tout nouveau en utilisant une compréhension.

>>> OrderedDict(Zip('123', 'abc'))
OrderedDict([('1', 'a'), ('2', 'b'), ('3', 'c')])
>>> oldkey, newkey = '2', 'potato'
>>> OrderedDict((newkey if k == oldkey else k, v) for k, v in _.viewitems())
OrderedDict([('1', 'a'), ('potato', 'b'), ('3', 'c')])

Modifier la clé elle-même, comme semble le poser cette question, est peu pratique car les clés dict sont généralement des objets immuables tels que des nombres, des chaînes ou des n-uplets. Au lieu d’essayer de modifier la clé, réaffecter la valeur à une nouvelle clé et supprimer l’ancienne, voici comment vous pouvez renommer en python.

594
wim

meilleure méthode en 1 ligne:

>>> d = {'test':[0,1,2]}
>>> d['test2'] = d.pop('test')
>>> d
{'test2': [0, 1, 2]}
53
Tcll

En utilisant un chèque pour newkey!=oldkey, vous pouvez ainsi:

if newkey!=oldkey:  
    dictionary[newkey] = dictionary[oldkey]
    del dictionary[oldkey]

Vous pouvez utiliser ceci OrderedDict recipe écrit par Raymond Hettinger et le modifier pour ajouter une méthode rename, mais il s'agira d'un O(N) en complexité:

_def rename(self,key,new_key):
    ind = self._keys.index(key)  #get the index of old key, O(N) operation
    self._keys[ind] = new_key    #replace old key with new key in self._keys
    self[new_key] = self[key]    #add the new key, this is added at the end of self._keys
    self._keys.pop(-1)           #pop the last item in self._keys
_

Exemple:

_dic = OrderedDict((("a",1),("b",2),("c",3)))
print dic
dic.rename("a","foo")
dic.rename("b","bar")
dic["d"] = 5
dic.rename("d","spam")
for k,v in  dic.items():
    print k,v
_

sortie:

_OrderedDict({'a': 1, 'b': 2, 'c': 3})
foo 1
bar 2
c 3
spam 5
_
10

Quelques personnes avant moi ont mentionné le truc .pop pour supprimer et créer une clé dans une ligne.

Personnellement, je trouve l’implémentation plus explicite plus lisible:

d = {'a': 1, 'b': 2}
v = d['b']
del d['b']
d['c'] = v

Le code ci-dessus renvoie {'a': 1, 'c': 2}

3
Uri Goren

Les autres réponses sont plutôt bonnes.Mais en python3.6, le dict normal a aussi de l’ordre. Il est donc difficile de garder la position de la clé en cas normal.

def rename(old_dict,old_name,new_name):
    new_dict = {}
    for key,value in Zip(old_dict.keys(),old_dict.values()):
        new_key = key if key != old_name else new_name
        new_dict[new_key] = old_dict[key]
    return new_dict
2
helloswift123

Si vous renommez toutes les clés du dictionnaire:

dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
new_keys = ['k4','k5','k6']

for key,n_key in Zip(dict,new_keys):
    dict[n_key] = dict.pop(key)
1

Dans Python 3.6 (et plus?), Je choisirais le one-liner suivant

test = {'a': 1, 'old': 2, 'c': 3}
old_k = 'old'
new_k = 'new'
new_v = 4  # optional

print(dict((new_k, new_v) if k == old_k else (k, v) for k, v in test.items()))

qui produit

{'a': 1, 'new': 4, 'c': 3}

Il convient de noter que, sans l’instruction print, le bloc-notes ipython console/jupyter présente le dictionnaire dans l’ordre de son choix ...

1
KeithWM

Même si c'est une liste de dict, il suffit de le convertir en chaîne.

NOTE: Assurez-vous de ne pas avoir les valeurs name same as key name.

Pourrait travailler pour quelqu'un

import json
d = [{'a':1,'b':2},{'a':2,'b':3}]
d = json.loads(json.dumps(d).replace('"a"','"newKey"'))
0
deusxmachine

@ helloswift123 J'aime votre fonction. Voici une modification pour renommer plusieurs clés en un seul appel:

def rename(d, keymap):
    """
    :param d: old dict
    :type d: dict
    :param keymap: [{:keys from-keys :values to-keys} keymap]
    :returns: new dict
    :rtype: dict
    """
    new_dict = {}
    for key, value in Zip(d.keys(), d.values()):
        new_key = keymap.get(key, key)
        new_dict[new_key] = d[key]
    return new_dict
0
skullgoblet1089

Supposons que vous souhaitiez renommer la clé k3 en k4:

temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
temp_dict['k4']= temp_dict('k3')
0
shishir bondre

Dans le cas où quelqu'un voudrait renommer toutes les clés en même temps en fournissant une liste avec les nouveaux noms:

def rename_keys(dict_, new_keys):
    """
     new_keys: type List(), must match length of dict_
    """

    # dict_ = {oldK: value}
    # d1={oldK:newK,} maps old keys to the new ones:  
    d1 = dict( Zip( list(dict_.keys()), new_keys) )

          # d1{oldK} == new_key 
    return {d1[oldK]: value for oldK, value in dict_.items()}
0
Sirmione

J'utilise la réponse de @wim ci-dessus, avec dict.pop () pour renommer des clés, mais j'ai trouvé un piège. En parcourant le dict pour changer les clés, sans séparer complètement la liste des anciennes clés de l'instance dict, il en a résulté le remplacement de nouvelles clés, la modification de clés dans la boucle et l'absence de certaines clés existantes.

Pour commencer, je l'ai fait comme suit:

for current_key in my_dict:
    new_key = current_key.replace(':','_')
    fixed_metadata[new_key] = fixed_metadata.pop(current_key)

J’ai trouvé que, de cette façon, le dictionnaire dictait sans cesse les clés, même s’il ne devait pas, c’est-à-dire les nouvelles clés, celles que j’avais changées! Je devais séparer complètement les instances les unes des autres pour (a) éviter de trouver mes propres clés modifiées dans la boucle for et (b) trouver des clés qui ne se trouvaient pas dans la boucle pour une raison quelconque.

Je fais ça maintenant:

current_keys = list(my_dict.keys())
for current_key in current_keys:
    and so on...

La conversion de my_dict.keys () en une liste était nécessaire pour se libérer de la référence au dict modifié. Le simple fait d'utiliser my_dict.keys () m'a maintenu lié à l'instance d'origine, avec des effets secondaires étranges.

0
excyberlabber