views:

231

answers:

7

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?

+3  A: 

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.

Ignacio Vazquez-Abrams
Lots of downvotes, but no comments...
Ignacio Vazquez-Abrams
+1 That's actually right (I don't understand why people downvote without stating their objections)...
3lectrologos
The downvotes were probably because you found a problem not a solution. It's something that can be solved, just not quite in the way that was asked.
James Brooks
He's the only one to answer the question, keys cannot be changed, which was what the question actually requested. Upvote.
Rhubarb
+3  A: 

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}}))
AndiDog
The same works in py2, just without the syntactic sugar: `def transform(multilevelDict): return dict((str(key)+"abc" , (transform(value) if isinstance(value, dict) else value)) for key, value in multilevelDict.items())`
THC4k
Correct, thanks for mentioning that.
AndiDog
A: 
>>> 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}}
gnibbler
+1  A: 
#! /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
Greg Bacon
A: 

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}}
unutbu
Straightforward and nicely done
telliott99
+1  A: 

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 ;-)

THC4k
+1  A: 

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)
Andrew