4
votes

Comment aplatir le dictionnaire seulement plus profond que 3 niveaux

Supposons que vous ayez ce dictionnaire

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

Et que vous vouliez que chaque dictionnaire imbriqué sur 3 (ou plus) soit aplati. Donc un résultat comme celui-ci.

{
    "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"
        }
    }
}

Comment y parvenir?

les balises et la structure du dictionnaire sont dynamiques (je veux refactoriser plusieurs dictionnaires avec des structures différentes mais une ligne dure à chaque troisième dictionnaire imbriqué)

Je sais que je peux parcourir chaque valeur, mais comment saurais-je quand j'ai atteint le troisième dictionnaire imbriqué?

{
    "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"
        }
    }
}

PS Je peux aplatir chaque dictionnaire à l'aide du module flatten_json


3 commentaires

Pouvez-vous expliquer quel problème vous essayez de résoudre avec cela? En général, l'aplatissement d'une structure comme celle-ci n'améliorera pas la gestion des données.


ce sera moche de gérer les données comme vous le souhaitez


Vous pouvez ajouter un paramètre "level" / "depth" à votre fonction loopDict et l'augmenter à chaque récursivité, c'est pourquoi vous savez quand vous avez atteint le troisième niveau.


4 Réponses :


0
votes

Je l'ai réparé!

Pour les personnes qui recherchent ça, j'ai fini par le réparer de cette façon.

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)

Vous pouvez ajouter ou supprimer des boucles for en fonction de la profondeur (il existe probablement une fonction récursive plus soignée qui peut le faire pour vous)


0 commentaires

0
votes

J'ai corrigé ça, mais tu étais plus rapide! Cependant, je partage ma réponse, peut-être que cela peut être utile

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 commentaires

0
votes

Vous pouvez utiliser la récursivité:

{
  "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"
     }
   }
}

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

Sortie:

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}


0 commentaires

1
votes

L'approche la plus simple consiste à diviser celle-ci en deux étapes. Faites une boucle sur input_dictionary jusqu'à la profondeur cible souhaitée. Ensuite, appelez une fonction d'aplatissement sur les dictionnaires les plus internes:

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

Ceci génère:

def flatten(d):
    for key, value in list(d.items()):
        if isinstance(value, dict):
            del d[key]
            for subkey, subvalue in value.items():
                newkey = key + '.' + subkey
                d[newkey] = subvalue

for v1 in input_dict.values():
    if isinstance(v1, dict):
        for v2 in v1.values():
            if isinstance(v2, dict):
                flatten(v2)

Si quelque chose de plus général est nécessaire, l'une ou les deux étapes peut être rendu récursif.

J'espère que cela vous aidera :-)


0 commentaires