Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recursively traverse multidimensional dictionary, dimension unknown

Tags:

python

I want to create a function to recursively traverse a multidimensional dictionary, where the dimensions are unknown.

Here is what I have come up with so far, but it doesn't seem to be working correctly. This will print out some key / values twice and they are not in order.

def walk_dict(d):
    for k,v in d.items():
        if isinstance(v, dict):
            walk_dict(v)
        else:
            print "%s %s" % (k, v) 

Here's a sample array:

d = {
        'plan_code': 'b',
        'quantity': '1',
        'account': {
            'account_code': 'b',
            'username': 'jdoe',
            'email': '[email protected]',
            'first_name': 'b',
            'last_name': 'b',
            'company_name': 'Company, LLC.',
            'billing_info': {
                'first_name': 'b',
                'last_name': 'b',
                'address1': '123 Test St',
                'city': 'San Francisco',
                'state': 'CA',
                'country': 'US',
                'zip': '94105',
                'credit_card': {
                    'number': '1',
                    'year': '2018',
                    'month': '12',
                    'verification_value': '123',
                },
            },
        },
    }
like image 465
imns Avatar asked Oct 05 '10 04:10

imns


4 Answers

I'm not sure what your ultimate goal is, but the code is doing what it is supposed to. You are seeing what you think are repeats of items because there are key/value combos like 'first_name':'b' that are both within 'account' and within 'billing_info' within 'account'. I'm not sure what order you are looking for, but dictionaries are unordered so your function to print them out will have to give them some order, for instance by replacing the following:

for k,v in d.items():

with

for k,v in sorted(d.items(),key=lambda x: x[0]):

or you'll need an ordered dictionary. You can also use the pprint module like so to give a nice print out of a dict:

>>> import pprint
>>> pprint.pprint(d)
{'account': {'account_code': 'b',
             'billing_info': {'address1': '123 Test St',
                              'city': 'San Francisco',
                              'country': 'US',
                              'credit_card': {'month': '12',
                                              'number': '1',
                                              'verification_value': '123',
                                              'year': '2018'},
                              'first_name': 'b',
                              'last_name': 'b',
                              'state': 'CA',
                              'zip': '94105'},
             'company_name': 'Company, LLC.',
             'email': '[email protected]',
             'first_name': 'b',
             'last_name': 'b',
             'username': 'jdoe'},
 'plan_code': 'b',
 'quantity': '1'}

However, I'm not fully sure what your end goal is here. Also, you are missing the keys when the values are dictionaries. I modified your code to do a similar thing to what pprint does in the following:

def walk_dict(d,depth=0):
    for k,v in sorted(d.items(),key=lambda x: x[0]):
        if isinstance(v, dict):
            print ("  ")*depth + ("%s" % k)
            walk_dict(v,depth+1)
        else:
            print ("  ")*depth + "%s %s" % (k, v) 

which for your example dict yields:

>>> walk_dict(d)
account
  account_code b
  billing_info
    address1 123 Test St
    city San Francisco
    country US
    credit_card
      month 12
      number 1
      verification_value 123
      year 2018
    first_name b
    last_name b
    state CA
    zip 94105
  company_name Company, LLC.
  email [email protected]
  first_name b
  last_name b
  username jdoe
plan_code b
quantity 1
like image 164
Justin Peel Avatar answered Nov 16 '22 01:11

Justin Peel


import json
print(json.dumps(d, indent=4))
like image 42
Chris Johnson Avatar answered Nov 16 '22 01:11

Chris Johnson


This does print the key, value pairs correctly. Can you point out which data gets repeated. There can be confusion based on the above data as these keys :

'first_name': 'b',
'last_name': 'b',

are part of two dictionaries - 'account' and 'billing_info'. So they will appear twice in output.

Also if you want some kind of order in which your dictionaries K,V should get printed use Ordered Dictionaries

  • http://docs.python.org/dev/library/collections.html#collections.OrderedDict
  • Key-ordered dict in Python
  • http://code.activestate.com/recipes/496761-a-more-clean-implementation-for-ordered-dictionary/
like image 43
pyfunc Avatar answered Nov 15 '22 23:11

pyfunc


As Justin Peel mentions, pprint.pprint will probably do what you want.

I think the problem with your code is that you should be printing the key first before recursing, i.e. change

    if isinstance(v, dict):
        walk_dict(v)

to

    if isinstance(v, dict):
        print k
        walk_dict(v)

Though in any case it's going to look pretty confusing unless you add indentation and such.

This sort of thing is actually pretty complicated; check out the code for pprint if you want to get some ideas.

like image 29
intuited Avatar answered Nov 15 '22 23:11

intuited