fonction python3 pour fusionner les dictionnaires

Aug 28 2020

J'ai un tas d'enregistrements JSON, chaque enregistrement avec un degré d'exhaustivité variable. En d'autres termes, l'enregistrement A peut contenir des clés ne figurant pas dans l'enregistrement B, et vice-versa. Pour mieux comprendre les données à l'intérieur, j'ai créé une fonction pour prendre N nombre d'enregistrements et les fusionner ensemble, créant un seul enregistrement Frankenstein contenant toutes les clés et une seule valeur pour chaque clé.

import sys
import json
def frankenstein(out, in_dict, key=None):
    if isinstance(in_dict, dict):
        for k, v in in_dict.items():
            if isinstance(in_dict[k], list) and v:
                out.setdefault(k, [])
                frankenstein(out[k], v, k)
            elif isinstance(in_dict[k], dict) and v:
                out.setdefault(k, {})
                frankenstein(out[k], v, k)
            elif v:
                out[k] = v
    elif isinstance(in_dict, list):
        s = {}
        for item in in_dict:
            if isinstance(item, dict):
                frankenstein(s, item)
            elif not out:
                out.append(item)
            if s:
                if not out:
                    out.append(s)
                else:
                    frankenstein(s, out[0])
                    out[0] = s
if __name__ == '__main__':
    l = [
        {
            "name": "foo bar",
            "experience": [
                {
                    "company": {
                        "name": "oracle",
                        "hq": "123 main st",
                        "size": 100
                    },
                    "function": [
                        {
                            "name": "go getter"
                        }
                    ],
                    "location": {
                        "doubleday": "publisher"
                    },
                    "animal": "horse"
                }
            ],
            "skills": ["programming", "eating"]
        },
        {
            "name": "poo dar",
            "experience": [
                {
                    "company": {
                        "name": "microsoft",
                        "url": "foo.bar/com"
                    },
                    "function": [
                        {
                            "name": "bread",
                            "level": "really high"
                        }
                    ],
                    "solitary": {
                        "fat": "cat"
                    },
                    "health": "no good"
                }
            ],
            "skills": ["igz"]
        },
        {
            "name": "poo mar",
            "experience": [
                {
                    "function": [
                        {
                            "zoo": "creature"
                        }
                    ],
                    "location": {
                        "taste": "food"
                    },
                    "ping": {
                        "pong": "bong"
                    }
                }
            ],
            "skills": ["woots own"]
        }
    ]
    out = {}
    for item in l:
        frankenstein(out, item)
    print(json.dumps(out, indent=4))

Voici la sortie du code:

{
    "name": "poo mar",
    "experience": [
        {
            "function": [
                {
                    "name": "bread",
                    "level": "really high",
                    "zoo": "creature"
                }
            ],
            "location": {
                "taste": "food",
                "doubleday": "publisher"
            },
            "ping": {
                "pong": "bong"
            },
            "company": {
                "name": "oracle",
                "url": "foo.bar/com",
                "hq": "123 main st",
                "size": 100
            },
            "solitary": {
                "fat": "cat"
            },
            "health": "no good",
            "animal": "horse"
        }
    ],
    "skills": [
        "programming"
    ]
}

J'ai testé la fonction et cela fonctionne. Ce que j'aimerais, ce sont des commentaires sur le code. Est-ce que je fais cela de la manière la plus efficace possible? Y a-t-il de meilleures façons de le faire?

Réponses

5 RootTwo Aug 31 2020 at 12:16

Le keyparamètre to frankenstein()ne semble être utilisé nulle part et peut être éliminé.

Utilisez des lignes vides pour diviser le code en petits morceaux logiques. Il facilite la lecture et la compréhension du code.

in_dict est un nom trompeur, car il peut s'agir d'une liste, d'un dict ou de tout autre chose.

Dans la for k, v in in_dict.items():boucle, in_dict[k]et vsont la même chose, vest testé 3 fois, et la valeur de retour de setdefault()est ignorée puis recherchée sur la ligne suivante. Il peut être réécrit comme ceci:

    for k, v in in_dict.items():
        if not v:
            continue

        if isinstance(v, (list, dict)):
            out_k = out.setdefault(k, v.__class__())
            frankenstein(out_k, v)

        else:
            out[k] = v

La logique de manipulation listssemble alambiquée. Par exemple, il semble qu'il speut être mis à jour à chaque fois dans la boucle et également ajouté à out[k]. La question n'énonce pas clairement les règles pour combiner les choses, alors peut-être que c'est correct. Un commentaire ou une doc-string expliquant le but de la fonction et les règles de fusion des valeurs serait utile.