Python recursively replace character in keys of nested dictionary?
Actually all of the answers contain a mistake that may lead to wrong typing in the result.
I'd take the answer of @ngenain and improve it a bit below.
My solution will take care about the types derived from dict
(OrderedDict
, defaultdict
, etc) and also about not only list
, but set
and tuple
types.
I also do a simple type check in the beginning of the function for the most common types to reduce the comparisons count (may give a bit of speed in the large amounts of the data).
Works for Python 3. Replace obj.items()
with obj.iteritems()
for Py2.
def change_keys(obj, convert): """ Recursively goes through the dictionary obj and replaces keys with the convert function. """ if isinstance(obj, (str, int, float)): return obj if isinstance(obj, dict): new = obj.__class__() for k, v in obj.items(): new[convert(k)] = change_keys(v, convert) elif isinstance(obj, (list, set, tuple)): new = obj.__class__(change_keys(v, convert) for v in obj) else: return obj return new
If I understand the needs right, most of users want to convert the keys to use them with mongoDB that does not allow dots in key names.
I used the code by @horejsek, but I adapted it to accept nested dictionaries with lists and a function that replaces the string.
I had a similar problem to solve: I wanted to replace keys in underscore lowercase convention for camel case convention and vice versa.
def change_dict_naming_convention(d, convert_function): """ Convert a nested dictionary from one convention to another. Args: d (dict): dictionary (nested or not) to be converted. convert_function (func): function that takes the string in one convention and returns it in the other one. Returns: Dictionary with the new keys. """ new = {} for k, v in d.iteritems(): new_v = v if isinstance(v, dict): new_v = change_dict_naming_convention(v, convert_function) elif isinstance(v, list): new_v = list() for x in v: new_v.append(change_dict_naming_convention(x, convert_function)) new[convert_function(k)] = new_v return new