Как сгладить словарь только глубже, чем 3 уровня - PullRequest
3 голосов
/ 10 мая 2019

Предположим, у вас есть этот словарь

{
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta": {
                "zeta1": "four",
                "zeta2": "second four"
            },
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}

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

{
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta.zeta1": "four",
            "zeta.zeta2": "second four",
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}

Как этого добиться?

теги и структура словаря являются динамическими (я хочу реорганизовать несколько словарей с различными структурами, но с трудомстрока в каждом третьем вложенном словаре)

Я знаю, что могу просмотреть все значения, но как узнать, когда я достиг третьего вложенного словаря?

def loopDict(d):
    for k, v in d.iteritems():
        if type(v) is dict:
            loopDict(v)
        else:
            print "{0} : {1}".format(k, v)

PS Я могу сгладить каждый словарьиспользуя модуль flatten_json

Ответы [ 3 ]

0 голосов
/ 10 мая 2019

Я исправил это, но ты был быстрее!Тем не менее, я делюсь своим ответом, может быть, он может быть полезным

d = {
    "alpha": "one",
    "beta": {
        "beta1": "two",
        "beta2": "second two"
    },
    "gamma": {
        "delta": {
            "delta1": "three",
            "delta2": "second three"
        },
        "epsilon": {
            "zeta": {
                "zeta1": "four",
                "zeta2": "second four"
            },
            "epsilon1": "five",
            "epsilon2": "second five"
        }
    }
}


def flatten_dict(d):
    def items():
        for key, value in d.items():
            if isinstance(value, dict):
                for subkey, subvalue in flatten_dict(value).items():
                    yield key + "." + subkey, subvalue
            else:
                yield key, value

    return dict(items())

def loopDict(d, depth):
    for k, v in d.items():
        if isinstance(v, dict):
            if depth > 0:
                d[k] = flatten_dict(v)
            if depth <= 0:
                loopDict(v, depth+1)

    return d

d = loopDict(d, 0)
print(d)
0 голосов
/ 10 мая 2019

Вы можете использовать рекурсию:

data = {'alpha': 'one', 'beta': {'beta1': 'two', 'beta2': 'second two'}, 'gamma': {'delta': {'delta1': 'three', 'delta2': 'second three'}, 'epsilon': {'zeta': {'zeta1': 'four', 'zeta2': 'second four'}, 'epsilon1': 'five', 'epsilon2': 'second five'}}}
def flatten(d, c = [], l = 1):
   for a, b in d.items():
     if not isinstance(b, dict):
       yield a if l < 3 else '.'.join(c+[a]), b
     else:
       if l > 2:
          yield from flatten(b, c=c+[a] if l > 2 else c, l=l+1)
       else:
          yield (a, list(flatten(b, c=c+[a] if l > 2 else c, l=l+1)))

def walk(d):
  return {a:b if not isinstance(b, list) else walk(b) for a, b in d}

import json
print(json.dumps(walk(list(flatten(data))), indent=4))

Выход:

{
  "alpha": "one",
  "beta": {
    "beta1": "two",
    "beta2": "second two"
  },
  "gamma": {
    "delta": {
        "delta1": "three",
        "delta2": "second three"
    },
    "epsilon": {
        "zeta.zeta1": "four",
        "zeta.zeta2": "second four",
        "epsilon1": "five",
        "epsilon2": "second five"
     }
   }
}
0 голосов
/ 10 мая 2019

Я исправил это!

Для людей, которые смотрят это, я закончил исправлять это таким образом.

xmldict = {yourdictionary}

for k, v in xmldict.items():
    if isinstance(v, dict):
        for ke, va in v.items():
            if isinstance(va, dict):
                for key, val in va.items():
                    if isinstance(val, dict):
                        for key1, val1 in val.items():
                            if isinstance(val1, dict):
                                xmldict[k][ke][key] = flatten(v)

Вы можете добавить или удалитьдля петель, зависящих от глубины (есть рекурсивная функция, которая может сделать это за вас)

...