Python de manière récursive remplacer des caractères dans les touches de imbriquée dictionnaire?
Je suis en train de créer une fonction générique qui remplace les points clés d'une imbriqués dictionnaire. J'ai un non-fonction générique qui va de 3 niveaux de profondeur, mais il doit y avoir un moyen de faire ce générique. Toute aide est appréciée! Mon code pour l'instant:
output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}}
def print_dict(d):
new = {}
for key,value in d.items():
new[key.replace(".", "-")] = {}
if isinstance(value, dict):
for key2, value2 in value.items():
new[key][key2] = {}
if isinstance(value2, dict):
for key3, value3 in value2.items():
new[key][key2][key3.replace(".", "-")] = value3
else:
new[key][key2.replace(".", "-")] = value2
else:
new[key] = value
return new
print print_dict(output)
Mise à JOUR: pour répondre à ma propre question, j'ai fait une solution en utilisant json object_hooks:
import json
def remove_dots(obj):
for key in obj.keys():
new_key = key.replace(".","-")
if new_key != key:
obj[new_key] = obj[key]
del obj[key]
return obj
output = {'key1': {'key2': 'value2', 'key3': {'key4 with a .': 'value4', 'key5 with a .': 'value5'}}}
new_json = json.loads(json.dumps(output), object_hook=remove_dots)
print new_json
- Toanswer à votre propre question, vous répondez à votre propre question, pas de le modifier.
- Utiliser ma solution parce que ma solution est dix fois plus rapide.
- plus rapide mais mal
- Bon moyen de le faire. Le object_hook vraiment simplifie l'ensemble de la chose, surtout dans mon cas où j'utilise une "clé" nommé "inclure" où il a besoin de façon récursive de la charge supplémentaire des fichiers JSON pour former un seul multidimensionnelle dictionnaire.
- Pour des raisons inexplicables, ce object_hook à l'aide de la méthode ci-dessus remove_dots() seulement remplacé quelques-uns des principaux noms. J'ai certains ce qui a permis à point. Est-il possible que cela soit lié à une étrange commande de problème dans le fichier obj.les touches de fonction ()? Je dois faire un commandés dict? Je pensais que Python3 n'ai pas eu le dict de la commande de problème?
Vous devez vous connecter pour publier un commentaire.
Oui, il existe une meilleure façon:
(Edit: C'est la récursivité, plus sur Wikipédia.)
J'ai utilisé le code par @horejsek, mais j'ai adapté pour qu'il accepte les dictionnaires imbriqués avec des listes et une fonction qui remplace la chaîne.
J'ai eu un problème similaire à résoudre: j'ai voulu remplacer les clés de souligner minuscules convention de chameaux cas de la convention et vice versa.
Voici une simple solution récursive qui traite avec des listes imbriquées et dictionnaries.
dict
classes dérivées de retour àdict
. Par exemple, vous risquez de perdre des touches de commande pourOrderedDict
. J'ai publié une amélioration de la réponse en fonction de votre one.En fait, toutes les réponses contiennent une erreur qui peut conduire à un mauvais tapant dans le résultat.
Je prendrais la réponse de @ngenain et de l'améliorer un peu en-dessous.
Ma solution prendra en charge les types dérivés de
dict
(OrderedDict
,defaultdict
, etc) et aussi de ne pas seulementlist
, maisset
ettuple
types.J'ai aussi de faire une simple vérification sur le type au début de la fonction pour les types les plus communs pour réduire les comparaisons count (peut donner un peu de vitesse dans les grandes quantités de données).
Fonctionne pour Python 3. Remplacer
obj.items()
avecobj.iteritems()
pour Py2.Si je comprends le besoin de droit, la plupart des utilisateurs qui veulent convertir les touches à utiliser avec mongoDB qui ne permettent pas de points dans les noms de clés.
Vous devez supprimer la clé d'origine, mais vous ne pouvez pas le faire dans le corps de la boucle, parce qu'il va jeter RunTimeError: dictionnaire changé de taille au cours d'une itération.
Pour résoudre ce problème, itérer une copie de l'objet d'origine, mais de modifier l'objet original:
TypeError: string indices must be integers
dansif hasattr(obj[k], '__getitem__'):
ligne.hasattr(...)
essayer:from collection import Mapping
et puisif isinstance(obj[k], Mapping)...
. Ce changement a le même objectif (en essayant de déterminer si la valeur est un [imbriquée] dictionnaire), mais il devrait être plus stable.Tout jllopezpino réponse fonctionne, mais seulement limitée à la commencer avec le dictionnaire, voici la mienne qui fonctionne avec la variable d'origine, est ou de liste dict.
Voici un 1-liner variante de @horejsek 's réponse en utilisant des dict de la compréhension pour ceux qui préfèrent:
J'ai uniquement testé en Python 2.7