python3 per unire i dizionari
Ho un sacco di record JSON, ogni record con un diverso grado di completezza. In altre parole, il record A può contenere chiavi non presenti nel record B e viceversa. Per avere una migliore comprensione dei dati all'interno, ho creato una funzione per prendere N numero di record e unirli insieme, creando un unico record di frankenstein contenente tutte le chiavi e un unico valore per ciascuna chiave.
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))
Questo è l'output del codice:
{
"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"
]
}
Ho testato la funzione e funziona. Quello che vorrei è un feedback per quanto riguarda il codice. Lo sto facendo nel modo più efficiente possibile? Ci sono modi migliori per farlo?
Risposte
Il keyparametro to frankenstein()non sembra essere utilizzato da nessuna parte e può essere eliminato.
Usa righe vuote per dividere il codice in blocchi logici più piccoli. Aiuta a leggere e comprendere il codice.
in_dictè un nome fuorviante, perché può essere un elenco, un dict o qualcos'altro.
Nel for k, v in in_dict.items():ciclo, in_dict[k]e vsono la stessa cosa, vviene testato 3 volte e il valore restituito di setdefault()viene scartato e quindi cercato nella riga successiva. Si può riscrivere così:
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 logica per la gestione listssembra contorta. Ad esempio, sembra che spossa essere aggiornato ogni volta attraverso il ciclo e anche aggiunto a out[k]. La domanda non indica chiaramente le regole per combinare le cose, quindi forse è corretto. Sarebbe utile un commento o una doc-string che spieghi lo scopo della funzione e le regole per unire i valori.