如何在python中迭代动态“深度”的词典?

时间:2010-08-12 03:16:11

标签: python algorithm dictionary iteration

我有一个具有各种“深度”的字典数据结构。 以“深度”为例,我的意思是: 当深度为1时,dict将如下:

{'str_key1':int_value1, 'str_key2:int_value2}

当深度为2时,dict将如下:

{'str_key1':
    {'str_key1_1':int_value1_1,
     'str_key1_2':int_value1_2},
 'str_key2':
    {'str_key2_1':int_value2_1, 
     'str_key2_2':int_value2_2} }

等等。

当我需要处理数据时,现在我正在这样做:

def process(keys,value):
  #do sth with keys and value
  pass

def iterate(depth,dict_data):
  if depth == 1:
    for k,v in dict_data:
      process([k],v)
  if depth == 2:
    for k,v in dict_data:
      for kk,vv, in v:
        process([k,kk],v)
  if depth == 3:
    .........

深度 n 时,我需要 n for循环。由于深度可以达到10,我想知道是否有更动态的方法来进行迭代而不必写出所有if和for子句。

感谢。

5 个答案:

答案 0 :(得分:4)

我不确定为什么每个人都在考虑递归(或递归消除) - 我只是执行depth个步骤,每个步骤通过向下扩展它来重建列表。

E.g:

def itr(depth, d):
  cp = [([], d)]
  for _ in range(depth):
    cp = [(lk+[k], v) for lk, d in cp for k, v in d.items()]
  for lk, ad in cp:
    process(lk, ad)
如果为了教学目的需要使其更具可读性,

使用更长的标识符和更低的代码密度易于“扩展”,但我认为逻辑很简单,可能不需要这样的处理(并且,为了它自己的缘故,冗长也有它的缺点; - )。

例如:

d = {'str_key1':
      {'str_key1_1':'int_value1_1',
       'str_key1_2':'int_value1_2'},
     'str_key2':
      {'str_key2_1':'int_value2_1', 
       'str_key2_2':'int_value2_2'} }

def process(lok, v):
  print lok, v

itr(2, d)

打印

['str_key2', 'str_key2_2'] int_value2_2
['str_key2', 'str_key2_1'] int_value2_1
['str_key1', 'str_key1_1'] int_value1_1
['str_key1', 'str_key1_2'] int_value1_2

(如果需要某些特定顺序,当然可以在cp)执行适当的排序。

答案 1 :(得分:3)

显而易见的答案是使用递归。但是,你可以在这里使用Python来做一些平滑的字体。这仍然是从根本上递归的 - 我们只是实现自己的堆栈。

def flatten(di):
     stack = [di]
     while stack:
         e = stack[-1]
         for k, v in e.items():
             if isinstance(v, dict):
                 stack.append(v)
             else:
                 yield k, v
         stack.remove(e)

然后,您可以执行以下操作:

for k, v in flatten(mycomplexdict):
     process(k, v)

答案 2 :(得分:2)

递归是你的朋友:

def process(keys,value):
  #do sth with keys and value
  pass

def iterate(depth, dict_data):
  iterate_r(depth, dict_data, [])

def iterate_r(depth, data, keys):
  if depth == 0:
    process(keys, data)
  else:
    for k,v in dict_data.items():
      iterate_r(depth-1, v, keys+[k])

答案 3 :(得分:2)

Reusive,请记住python只能递归1000次:

def process(key, value):
    print key, value

def process_dict(dict, callback):
    for k, v in dict.items():
        if hasattr(v, 'items'):
            process_dict(v, callback)
        else:
            callback(k, v)

d = {'a': 1, 'b':{'b1':1, 'b2':2, 'b3':{'bb1':1}}}
process_dict(d, process)

打印:

a 1
b1 1
b2 2
bb1 1

答案 4 :(得分:1)

假设您想要一个固定的深度(大多数其他答案似乎假设您要递归到最大深度),并且您需要保留原始问题中的路径,这是最直接的解决方案:

def process_dict(d, depth, callback, path=()):
  for k, v in d.iteritems():
    if depth == 1:
      callback(path + (k,), v)
    else:
      process_dict(v, depth - 1, callback, path + (k,))

这是一个实际的例子:

>>> a_dict = {
...     'dog': {
...         'red': 5,
...         'blue': 6,
...     },
...     'cat': {
...         'green': 7,
...     },
... }
>>> def my_callback(k, v):
...   print (k, v)
...
>>> process_dict(a_dict, 1, my_callback)
(('dog',), {'blue': 6, 'red': 5})
(('cat',), {'green': 7})
>>> process_dict(a_dict, 2, my_callback)
(('dog', 'blue'), 6)
(('dog', 'red'), 5)
(('cat', 'green'), 7)