Выровнять диктофон произвольной глубины - PullRequest
0 голосов
/ 31 декабря 2018

Я получаю из другого скрипта словарь, содержащий различные типы, в частности, другие словари или списки, которые могут содержать другие словари в качестве значений.

Теперь я хочу создать один плоский словарь.Ключи могут присутствовать несколько раз в инкапсулированных словарях.Для меня самый внутренний ключ содержит новейшую информацию, поэтому я думаю, что dict.update - это правильная процедура, применяемая при переваривании «внутреннего» диктата.Под «внутренним» диктом я подразумеваю словарь, содержащий некоторое значение самого внешнего словаря.

Теперь я понимаю, как сгладить словарь на 1 уровень.С чем я борюсь, чтобы сгладить его произвольным количеством уровней.

Простой пример типа словаря, с которым я имею дело:

d = {1: {6: {7: {2: {'a'}}}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}

Моя попытка работает нормально дляодин уровень глубины:

dd = dict()
for k, v in d.items():
    if isinstance(v, dict):
        dd.update(v)
    elif isinstance(v, list):
        for el in v:
            if isinstance(el, dict):
                dd.update(el)
        dd[k] = [el for el in v if not isinstance(el, dict)]
    else:
        dd[k] = v

Это дает мне:

Out[56]:  {6: {7: {2: {'a'}}}, 2: 'b', 4: {2: 'c'}, 1: 'a', 5: ['a', 'b']}

Что это должно дать:

{2: 'a', 5: ['a', 'b']}

Обратите внимание на значение ключа 2: 'c' и нет (как я понял сейчас) 'b'.Это должно быть потому, что самое внутреннее значение для ключа 2 равно 'c', а не 'b'.

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

Любая помощь очень ценится!

Ответы [ 2 ]

0 голосов
/ 31 декабря 2018

Вы можете использовать рекурсию с генератором и сохранить счетчик для определения глубины:

d = {1: {6: {7: {2: {'a'}}}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}
def flatten(_d, _depth = 0):
  for a, b in _d.items():
     if isinstance(b, list):
       yield [a, [i for i in b if not isinstance(i, dict)], _depth]
       for c in b:
          if isinstance(c, dict):
             yield from flatten(c, _depth+1)
     elif isinstance(b, dict):
        yield from flatten(b, _depth+1)
     else:
        yield [a, b, _depth]

_result = {}
for a, b, c in flatten(d):
  if a not in _result:
     _result[a] = [b, c]
  else:
     if _result[a][-1] < c:
       _result[a] = [b, c]
print({a:b for a, [b, c] in _result.items()})

Выход:

{2: {'a'}, 5: ['a', 'b'], 1: 'a'}
0 голосов
/ 31 декабря 2018

Ваш подход правильный.Но вы обновили dict рекурсивно, чтобы он работал на любом количестве уровней

def flatten(d):
    dd = dict()
    for k, v in d.items():
        if isinstance(v, dict):
            dd.update(flatten(v))
        elif isinstance(v, list):
            for el in v:
                if isinstance(el, dict):
                    dd.update(flatten(el))
            dd[k] = [el for el in v if not isinstance(el, dict)]
        else:
            dd[k] = v

    return dd

d = {1: {2: {'a'}}, 2: 'b', 3: {4: {2: 'c'}}, 5: ['a', 'b', {1: 'a'}]}
print flatten(d)
# {2: 'c', 1: 'a', 5: ['a', 'b']}
...