user1741339
user1741339

Reputation: 515

"Flattening" a list of dictionaries

So my aim is to go from:

fruitColourMapping = [{'apple': 'red'}, {'banana': 'yellow'}]

to

finalMap = {'apple': 'red', 'banana': 'yellow'}

A way I got is:

 from itertools import chain
 fruits = list(chain.from_iterable([d.keys() for d in fruitColourMapping]))
 colour = list(chain.from_iterable([d.values() for d in fruitColourMapping]))
 return dict(zip(fruits, colour))

Is there any better more pythonic way?

Upvotes: 29

Views: 40112

Answers (9)

pylang
pylang

Reputation: 44485

Given

d1, d2 = [{'apple': 'red'}, {'banana': 'yellow'}]

Code

In Python 3.5, dictionary unpacking was introduced (see PEP 448):

{**d1, **d2}
# {'apple': 'red', 'banana': 'yellow'}

In Python 3.9, the merge operator was introduced:

d1 | d2
# {'apple': 'red', 'banana': 'yellow'}

Upvotes: 5

nightwuffle
nightwuffle

Reputation: 341

I came up with a interesting one liner.

>>> a = [{"wow": 1}, {"ok": 2}, {"yeah": 3}, {"ok": [1,2,3], "yeah": True}]
>>> a = dict(sum(map(list, map(dict.items, a)), []))
>>> a
{'wow': 1, 'ok': [1, 2, 3], 'yeah': True}

Upvotes: 5

hankeong
hankeong

Reputation: 21

You could also try:

finalMap = dict(item for mapping in fruitColourMapping for item in mapping.items())

Upvotes: 2

Adam
Adam

Reputation: 15803

Why copy at all?

In Python 3, you can use the new ChainMap:

A ChainMap groups multiple dicts (or other mappings) together to create a single, updateable view.
The underlying mappings are stored in a list. That list is public and can accessed or updated using the maps attribute. There is no other state. Lookups search the underlying mappings successively until a key is found. In contrast, writes, updates, and deletions only operate on the first mapping.

All you need is this (do change the names to abide by Python naming conventions):

from collections import ChainMap
fruit_colour_mapping = [{'apple': 'red'}, {'banana': 'yellow'}]
final_map = ChainMap(*fruit_colour_mapping)

And then you can use all the normal mapping operations:

# print key value pairs:
for element in final_map.items():
    print(element)

# change a value:
final_map['banana'] = 'green'    # supermarkets these days....

# access by key:
print(final_map['banana'])

Upvotes: 45

hughdbrown
hughdbrown

Reputation: 49013

Approach

Use reduce to apply each dict to an empty initializer. Since dict.update always returns None, use d.update(src) or d to give reduce the desired return value.

Code

final_dict = reduce(lambda d, src: d.update(src) or d, dicts, {})

Test

>>> dicts = [{'a': 1, 'b': 2}, {'b': 3, 'c': 4}, {'a': 6}]
>>> final_dict = reduce(lambda d, src: d.update(src) or d, dicts, {})
>>> final_dict
{'a': 6, 'c': 4, 'b': 3}

Upvotes: 6

Pavel Anossov
Pavel Anossov

Reputation: 62908

{k: v for d in fruitColourMapping for k, v in d.items()}

Upvotes: 37

Daniel Roseman
Daniel Roseman

Reputation: 599580

dict(d.items()[0] for d in fruitColourMapping)

Upvotes: 6

Silas Ray
Silas Ray

Reputation: 26150

Rather than deconstructing and reconstructing, just copy and update:

final_map = {}
for fruit_color_definition in fruit_color_mapping:
    final_map.update(fruit_color_definition)

Upvotes: 14

nneonneo
nneonneo

Reputation: 179412

finalMap = {}
for d in fruitColourMapping:
    finalMap.update(d)

Upvotes: 32

Related Questions