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é.
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.
meilleure méthode en 1 ligne:
>>> d = {'test':[0,1,2]}
>>> d['test2'] = d.pop('test')
>>> d
{'test2': [0, 1, 2]}
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
_
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}
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
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)
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 ...
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"'))
@ 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
Supposons que vous souhaitiez renommer la clé k3 en k4:
temp_dict = {'k1':'v1', 'k2':'v2', 'k3':'v3'}
temp_dict['k4']= temp_dict('k3')
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()}
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.