Lista de diccionarios:
data = [{ 'a':{'l':'Apple', 'b':'Milk', 'd':'Meatball'}, 'b':{'favourite':'coke', 'dislike':'juice'} }, { 'a':{'l':'Apple1', 'b':'Milk1', 'd':'Meatball2'}, 'b':{'favourite':'coke2', 'dislike':'juice3'} }, ... ]Necesito unir todos los diccionarios anidados para llegar al resultado esperado:
[{'d': 'Meatball', 'b': 'Milk', 'l': 'Apple', 'dislike': 'juice', 'favourite': 'coke'}, {'d': 'Meatball2', 'b': 'Milk1', 'l': 'Apple1', 'dislike': 'juice3', 'favourite': 'coke2'}]Intento la comprensión de listas anidadas, pero no puedo unir dict juntos:
L = [y for x in data for y in x.values()] print (L) [{'d': 'Meatball', 'b': 'Milk', 'l': 'Apple'}, {'dislike': 'juice', 'favourite': 'coke'}, {'d': 'Meatball2', 'b': 'Milk1', 'l': 'Apple1'}, {'dislike': 'juice3', 'favourite': 'coke2'}]Estoy buscando la solución más rápida.
Puede hacer lo siguiente, usando itertools.chain :
>>> from itertools import chain # timeit: ~3.40 >>> [dict(chain(*map(dict.items, d.values()))) for d in data] [{'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'favourite': 'coke', 'dislike': 'juice'}, {'l': 'Apple1', 'b': 'Milk1', 'dislike': 'juice3', 'favourite': 'coke2', 'd': 'Meatball2'}] El uso de chain , map , * hace que esta expresión sea una abreviatura de la siguiente comprensión doblemente anidada que en realidad funciona mejor en mi sistema (Python 3.5.2) y no es mucho más larga:
# timeit: ~2.04 [{k: v for x in d.values() for k, v in x.items()} for d in data] # Or, not using items, but lookup by key # timeit: ~1.67 [{k: x[k] for x in d.values() for k in x} for d in data] El enfoque de bucle y actualización de RoadRunner supera a estos dos de una sola línea en timeit: ~1.37
Puede hacer esto con 2 bucles anidados y dict.update() para agregar diccionarios internos a un diccionario temporal y agregarlo al final:
L = [] for d in data: temp = {} for key in d: temp.update(d[key]) L.append(temp) # timeit ~1.4 print(L)Qué salidas:
[{'l': 'Apple', 'b': 'Milk', 'd': 'Meatball', 'favourite': 'coke', 'dislike': 'juice'}, {'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2', 'favourite': 'coke2', 'dislike': 'juice3'}]Puede usar functools.reduce junto con una lista simple de comprensión para aplanar la lista de dictados
>>> from functools import reduce >>> data = [{'b': {'dislike': 'juice', 'favourite': 'coke'}, 'a': {'l': 'Apple', 'b': 'Milk', 'd': 'Meatball'}}, {'b': {'dislike': 'juice3', 'favourite': 'coke2'}, 'a': {'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2'}}] >>> [reduce(lambda x,y: {**x,**y},d.values()) for d in data] >>> [{'dislike': 'juice', 'l': 'Apple', 'd': 'Meatball', 'b': 'Milk', 'favourite': 'coke'}, {'dislike': 'juice3', 'l': 'Apple1', 'd': 'Meatball2', 'b': 'Milk1', 'favourite': 'coke2'}]El punto de referencia de tiempo es el siguiente:
>>> import timeit >>> setup = """ from functools import reduce data = [{'b': {'dislike': 'juice', 'favourite': 'coke'}, 'a': {'l': 'Apple', 'b': 'Milk', 'd': 'Meatball'}}, {'b': {'dislike': 'juice3', 'favourite': 'coke2'}, 'a': {'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2'}}] """ >>> min(timeit.Timer("[reduce(lambda x,y: {**x,**y},d.values()) for d in data]",setup=setup).repeat(3,1000000)) >>> 1.525032774952706Punto de referencia de tiempo de otras respuestas en mi máquina
>>> setup = """ data = [{'b': {'dislike': 'juice', 'favourite': 'coke'}, 'a': {'l': 'Apple', 'b': 'Milk', 'd': 'Meatball'}}, {'b': {'dislike': 'juice3', 'favourite': 'coke2'}, 'a': {'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2'}}] """ >>> min(timeit.Timer("[{k: v for x in d.values() for k, v in x.items()} for d in data]",setup=setup).repeat(3,1000000)) >>> 2.2488374650129117 >>> min(timeit.Timer("[{k: x[k] for x in d.values() for k in x} for d in data]",setup=setup).repeat(3,1000000)) >>> 1.8990078769857064 >>> code = """ L = [] for d in data: temp = {} for key in d: temp.update(d[key]) L.append(temp) """ >>> min(timeit.Timer(code,setup=setup).repeat(3,1000000)) >>> 1.4258553800173104 >>> setup = """ from itertools import chain data = [{'b': {'dislike': 'juice', 'favourite': 'coke'}, 'a': {'l': 'Apple', 'b': 'Milk', 'd': 'Meatball'}}, {'b': {'dislike': 'juice3', 'favourite': 'coke2'}, 'a': {'l': 'Apple1', 'b': 'Milk1', 'd': 'Meatball2'}}] """ >>> min(timeit.Timer("[dict(chain(*map(dict.items, d.values()))) for d in data]",setup=setup).repeat(3,1000000)) >>> 3.774383604992181