Как повторить дикт динамических «глубин» в питоне? - PullRequest
1 голос
/ 12 августа 2010

У меня есть dict структура данных с различной "глубиной".Под «глубиной» я имею в виду, например: Когда глубина равна 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 .Поскольку глубина может доходить до 10, мне интересно, есть ли более динамичный способ выполнения итерации без необходимости выписывать все предложения if и for.

Спасибо.

Ответы [ 5 ]

4 голосов
/ 12 августа 2010

Я не уверен, почему все думают с точки зрения рекурсии (или устранения рекурсии) - я бы просто сделал depth шагов, каждый из которых перестраивает список, расширяя его еще на один уровень вниз.

например:.

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

3 голосов
/ 12 августа 2010

Очевидный ответ - использовать рекурсию.Но вы можете сделать что-то приятное с 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 голосов
/ 12 августа 2010

Recusive, просто имейте в виду, 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
2 голосов
/ 12 августа 2010

Рекурсия - твой друг:

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])
1 голос
/ 12 августа 2010

Предполагая, что вам нужна фиксированная глубина (большинство других ответов, по-видимому, предполагают, что вы хотите вернуться к максимальной глубине), и вам нужно сохранить путь, как в исходном вопросе, вот самое простое решение:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...