2010-10-05 46 views
9

我想要创建一个递归遍历维度未知的多维字典的函数。递归遍历多维字典,维度未知

这是我到目前为止,但它似乎没有正常工作。这将打印出一些键/值两次,他们不是为了。

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

这里的一个样本阵列:

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', 
       }, 
      }, 
     }, 
    } 
+0

所以你有什么问题吗? – SingleNegationElimination 2010-10-05 04:20:15

回答

13

我不是确定你的最终目标是什么,但代码是做它应该做的。您看到了您认为重复的项目,因为有'/'这样的键/值组合,它们都位于“账户”内的“账户”和“账单信息”内的'账户'中。我不知道你在找什么顺序,但字典是无序的,所以你的函数打印出来必须给他们一些订单,例如通过更换以下:

for k,v in d.items(): 

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

或者您将需要一个有序的词典。您也可以使用pprint模块像这样给出一个不错的打印出一个字典的:

>>> 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'} 

不过,我不能完全确定你的最终目标是在这里。此外,当值是字典时,您缺少键。我修改了代码,做类似的事情在做什么pprint如下:

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) 

这对于你的榜样字典产量:

>>> 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 
2

这不正确地打印键,值对。你能指出哪些数据重复。根据上述数据,这些密钥可能会产生混淆:

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

是两个字典 - “帐户”和“billing_info”的一部分。所以他们会在输出中出现两次。

此外,如果你想要某种顺序的字典K,V应该得到印刷使用有序字典

+0

我只是抓住了那个词典,没有注意到重复。以为我做错了什么。感谢您指出了这一点。 – imns 2010-10-05 04:44:24

0

你的代码工作精细完美的,但它确实你说什么它来。

我在输出中看到的唯一重复是first_name和last_name,它们实际上定义了两次(在不同的字典中)。

至于'乱序'它是一本字典,它没有保证的顺序。也许它确实如此,但它将基于内部表示形式,您不应该依赖它。

你需要做的是什么样的,你希望它出来数据的方式。您也可能需要输出子字典的键值,以使输出更容易理解。

1

由于Justin Peelmentions,pprint.pprint可能会做你想做的。

我觉得你的代码的问题是,你应该先递归之前打印的关键,即在任何情况下更改

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

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

虽然它会看起来非常混乱除非你添加缩进等。

这样的事情实际上是非常复杂的;如果你想得到一些想法,请查看pprint的代码。

0

在Python,词典是由密钥索引。键可以是任何不可变类型,如字符串或数字。除非按键排序,否则它们将始终以任意顺序返回。由于这个事实,您的walk_dict正在打印看似随机的结果。

以下为walk_dict其示例打印所有的键和值。我在字典的每个级别对他们的键进行了排序。另外,我印了每个键。您的代码在递归之前未打印一个键。最后,我添加了字符串填充以强调字典的每个级别。文件测试全部通过。我希望这可以帮助你建立你的最终功能。

import doctest 


def walk_dict(seq, level=0): 
    """Recursively traverse a multidimensional dictionary and print all 
    keys and values. 

    >>> d = {'dog': 'dusty', 'cat': 'fluffy', 'bird': 'chirpy'} 
    >>> walk_dict(d) 
    bird chirpy 
    cat fluffy 
    dog dusty 
    >>> d = {'location': 'home', 'animals':{'dog': 'dusty', 'cat': 'fluffy', 'bird': 'chirpy'}} 
    >>> walk_dict(d) 
    animals 
     bird chirpy 
     cat fluffy 
     dog dusty 
    location home 
    >>> d = {'location': 'home', 'animals':{'dog': 'dusty', 'cat': 'fluffy', 'bird': {'name':'chirpy', 'color':'blue'}}} 
    >>> walk_dict(d) 
    animals 
     bird 
     color blue 
     name chirpy 
     cat fluffy 
     dog dusty 
    location home 
    >>> 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', \ 
        }, \ 
       }, \ 
      }, \ 
     } 
    >>> 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 
    """ 
    items = seq.items() 
    items.sort() 
    for v in items: 
     if isinstance(v[1], dict): 
      # Print the key before make a recursive call 
      print "%s%s" % (" " * level, v[0]) 
      nextlevel = level + 1 
      walk_dict(v[1], nextlevel) 
     else: 
      print "%s%s %s" % (" " * level, v[0], v[1]) 


if __name__ == '__main__': 
    doctest.testmod() 
3

>>> import json

>>> print json.dumps(d, indent=4)

+1

在我的情况下,我需要这样做正是因为'json.dumps'不能处理结构中的某些对象。 – OrangeDog 2017-05-03 16:43:32

+0

的'jsonpickle'库做代表的对象类型'json'扼流圈上的一个出乎意料的好工作 - 尝试。 – 2017-05-03 19:47:30

1

这里是由Justin皮尔接受的答案返回其结果为OrderedDict不是打印结果的变化。

from collections import OrderedDict 

def sort_by_keys(dct,): 
    new_dct = OrderedDict({}) 
    for key, val in sorted(dct.items(), key=lambda (key, val): key): 
     if isinstance(val, dict): 
      new_dct[key] = sort_by_keys(val) 
     else: 
      new_dct[key] = val 
    return new_dct