How to change the keys of a dictionary?

Viewed 87833

Let's say I have a pretty complex dictionary.

{'fruit':'orange','colors':{'dark':4,'light':5}}

Anyway, my objective is to scan every key in this complex multi-level dictionary. Then, append "abc" to the end of each key.

So that it will be:

{'fruitabc':'orange','colorsabc':{'darkabc':4,'lightabc':5}}

How would you do that?

15 Answers

Keys cannot be changed. You will need to add a new key with the modified value then remove the old one, or create a new dict with a dict comprehension or the like.

For example like this:

def appendabc(somedict):
    return dict(map(lambda (key, value): (str(key)+"abc", value), somedict.items()))

def transform(multilevelDict):
    new = appendabc(multilevelDict)

    for key, value in new.items():
        if isinstance(value, dict):
            new[key] = transform(value)

    return new

print transform({1:2, "bam":4, 33:{3:4, 5:7}})

This will append "abc" to each key in the dictionary and any value that is a dictionary.

EDIT: There's also a really cool Python 3 version, check it out:

def transform(multilevelDict):
    return {str(key)+"abc" : (transform(value) if isinstance(value, dict) else value) for key, value in multilevelDict.items()}

print(transform({1:2, "bam":4, 33:{3:4, 5:7}}))
>>> mydict={'fruit':'orange','colors':{'dark':4,'light':5}}

>>> def f(mydict):
...  return dict((k+"abc",f(v) if hasattr(v,'keys') else v) for k,v in mydict.items())
... 
>>> f(mydict)
{'fruitabc': 'orange', 'colorsabc': {'darkabc': 4, 'lightabc': 5}}

My understanding is that you can't change the keys, and that you would need to make a new set of keys and assign their values to the ones the original keys were pointing to.

I'd do something like:

def change_keys(d):
  if type(d) is dict:
    return dict([(k+'abc', change_keys(v)) for k, v in d.items()])
  else:
    return d

new_dict = change_keys(old_dict)
#! /usr/bin/env python

d = {'fruit':'orange', 'colors':{'dark':4,'light':5}}

def add_abc(d):
  newd = dict()
  for k,v in d.iteritems():
    if isinstance(v, dict):
      v = add_abc(v)
    newd[k + "abc"] = v
  return newd

d = add_abc(d)
print d

Something like that

def applytoallkeys( dic, func ):
    def yielder():
        for k,v in dic.iteritems():
            if isinstance( v, dict):
                yield func(k), applytoallkeys( v, func )
            else:
                yield func(k), v
    return dict(yielder())

def appendword( s ):
    def appender( x ):
        return x+s
    return appender

d = {'fruit':'orange','colors':{'dark':4,'light':5}}
print applytoallkeys( d, appendword('asd') )

I kinda like functional style, you can read just the last line and see what it does ;-)

You could do this with recursion:

import collections
in_dict={'fruit':'orange','colors':{'dark':4,'light':5}}

def transform_dict(d):
    out_dict={}
    for k,v in d.iteritems():
        k=k+'abc'
        if isinstance(v,collections.MutableMapping):
            v=transform_dict(v)            
        out_dict[k]=v
    return out_dict
out_dict=transform_dict(in_dict)
print(out_dict)

# {'fruitabc': 'orange', 'colorsabc': {'darkabc': 4, 'lightabc': 5}}

Based on @AndiDog's python 3 version and similar to @sxc731's version but with a flag for whether to apply it recursively:

def transform_keys(dictionary, key_fn, recursive=True):
    """
    Applies function to keys and returns as a new dictionary.

    Example of key_fn:
      lambda k: k + "abc"
    """
    return {key_fn(key): (transform_keys(value, key_fn=key_fn, recursive=recursive)
                          if recursive and isinstance(value, dict) else value)
            for key, value in dictionary.items()}
Related