简体   繁体   中英

How to convert this lists of dicts to a new dict

I wanna convert this list of dicts:

input_list = [
    {'a': 5,'b': 7},
    {'a': 3,'b': 4},
]

to this:

result_dict = {
    'a': [5, 3],
    'b': [7, 4]
}

I somehow can't manage to do this.

Can someone help me out there please.

A vanilla Python approach

result = {}
for subdic in data:
    for k, v in subdic.items():
        result.setdefault(k, []).append(v)

Here we iterate over the items and we add an empty list to the result dict in case the key is not yet in the dictionary. Regardless whether there was already a list, we append v to that list.

Using defaultdict

We can make it more elegant by using defaultdict from collections :

from collections import defaultdict

result = defaultdict(list)
for subdic in data:
    for k, v in subdic.items():
        result[k].append(v)

Here we basically make abstraction of the setdefault (and we also save on constructing useless empty lists). In case the output should be a dict (and not a defaultdict ), we can end the function with:

result = dict(result)

Using pandas

If every dictionary contains the same keys, we can use pandas:

from pandas import DataFrame

result = DataFrame(data).to_dict(orient='list')
result_dict = {}
for index, row_dict in enumerate(input_list):
    for key, item_dict in row_dict.items():
        if not key in result_dict:
            result_dict[key] = []

        result_dict[key].append(row_dict[key])

hmm I think this does it. maybe someone comes up with a better approach..

So here is something that might help you.

It uses defaultdict construct and that might be an overkill, but it cleanly solves the task.

from collections import defaultdict

input_list = [
    {'a': 5, 'b': 7},
    {'a': 3, 'b': 4},
]

result_dict = defaultdict(list)

for i, j in zip(*[i.items() for i in input_list]):
    result_dict[i[0]].append(i[1])
    result_dict[j[0]].append(j[1])

print dict(result_dict)
In [1]: input_list = [
   ...:     {'a': 5,'b': 7},
   ...:     {'a': 3,'b': 4},
   ...: ]

In [2]: result_dict = {}

In [3]: for d in input_list:
   ...:     for k, v in d.items():
   ...:         if k not in result_dict:
   ...:             result_dict[k] = [v]
   ...:         else:
   ...:             result_dict[k].append(v)
   ...:             

In [4]: result_dict
Out[4]: {'a': [5, 3], 'b': [7, 4]}

One-liner

{y[0][0]: list(zip(*y)[1]) for y in zip(*[x.items() for x in input_list])}

A bit risky, we heavily rely on .items() returning keys in the same order each time.

A slightly more verbose solution but this also works:

from itertools import groupby
from itertools import chain
from operator import itemgetter

input_list = [
    {'a': 5,'b': 7},
    {'a': 3,'b': 4},
]

all_lsts = sorted(chain.from_iterable(d.items() for d in input_list))

group = dict((k, list(map(itemgetter(1), g))) for _, g in groupby(all_lsts, key=itemgetter(0)))

print(group)
# {'a': [3, 5], 'b': [4, 7]}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM