0

How should I define a function parsedic() which works like?

dic={0:0,
     1:{0:0,
        1:1,
        2:{0:0,},},
     2:{0:{1:0,
           0:{0:0}},},
     3:0}

def parsedic(...):
    ...

print parsedic(dic)

results:

0->0
3->0
1.0->0
1.1->1
1.2.0->0
2.0.0.0->0
2.0.1->0

The type of the key of the dict can only be a number or string, and the value can only be a number, string, or dict.

(To avoid misunderstandings, I deleted the words which showed how I've tried to solve this question for a long time.)

martineau
  • 119,623
  • 25
  • 170
  • 301
tcpiper
  • 2,456
  • 2
  • 28
  • 41
  • 2
    At least, I *think* it is. Your question is not clear, by far. What are you asking, actually? – Martijn Pieters Oct 08 '13 at 12:55
  • @kojiro where do you see floats? – sloth Oct 08 '13 at 12:56
  • @Martijn Pieters,I saw the question you mentioned,but I don't think mine is a duplicate of yours.I ask this question only because I just came up with it when I tried to solve [this problem](http://stackoverflow.com/questions/19221965/python-2-7-how-to-define-a-super-powerful-class-style-dict-object).I ask this question **not** to solve another question.So,actually,just curiosity:-) – tcpiper Oct 08 '13 at 13:24
  • @Pythoner: retracted the vote. Still not sure what exactly you were asking for.. – Martijn Pieters Oct 08 '13 at 13:26

2 Answers2

7

The simplest way to "flatten" a dict is a recursive generator like this:

def parse(dic):
    for k, v in dic.items():
        if isinstance(v, dict):
            for p in parse(v):
                yield [k] + p
        else:
            yield [k, v]

lst = list(parse(dic))

This creates a list of lists [[key,key,key,value],[key,key,val] etc], for your example it will be:

[[0, 0], [1, 0, 0], [1, 1, 1], [1, 2, 0, 0], [2, 0, 0, 0, 0], [2, 0, 1, 0], [3, 0]]

To print in the desired format just iterate over this list:

for row in parse(dic):
    row = map(str, row)
    print '.'.join(row[:-1]) + '->' + row[-1]

This answers your question, however it would be helpful if you tell us why you need this transformation in the first place. Maybe there's a better way.

georg
  • 211,518
  • 52
  • 313
  • 390
4

This approach keeps tracks of the current keys on a path to a value which isn't a dict.

def parsedic(d,currHist=[]):
    for k,v in d.items(): #go over dict's key,value pairs
        newHist = currHist + [k] #add the current key to the 'path' of keys
        if isinstance(v,dict): #if that value is a dictionary then we need to go over it's key/vals                 
            parsedic(v,currHist=newHist) #recurse...
        else:  #base case
            print "%s->%d"%('.'.join(map(str,newHist)),v) #print out the path separated by '.' and then -> to the value

parsedic(dic)

Output (note it isn't in the same order because iteration over key,value pairs will be different):

>>> 
0->0
1.0->0
1.1->1
1.2.0->0
2.0.0.0->0
2.0.1->0
3->0

A slightly harder to read approach which doesn't create a new list at each recursion is:

    currHist.append(k) #add the current key
    if isinstance(v,dict):
        parsedic(v,currHist=currHist)
    else:
        print "%s->%d"%('.'.join(map(str,currHist)),v)
    currHist.pop() #remove that same key
HennyH
  • 7,794
  • 2
  • 29
  • 39