Combine values of same keys in a list of dicts

I have a list of dictionaries in the following format:

foo = [
    {'a': 'x', 'b': 'y', 'c': 'z'},
    {'a': 'j', 'c': 'z'}
]

I want to group this list of dictionaries into a single dictionary, like:

bar = {
    'a': ['x', 'j'],
    'b': ['y', None],
    'c': ['z', 'z']
}

What I’ve currently done is, looping through all the dicts in foo and create a list of keys and then looping again over the same to create bar. I wonder whether there is a simpler way to accomplish this. Can anyone help?

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

bar = {
    k: [d.get(k) for d in foo]
    for k in set().union(*foo)
}

Things to google:

  • python list comprehension
  • python dict comprehension
  • python star
  • python dict get
  • python set union

Solution 2

I am just going to complement Alex Hall solution here, so that it does not return a lot of "None" values:

def merge_dictionary_list(dict_list):
  return {
    k: [d.get(k) for d in dict_list if k in d] # explanation A
    for k in set().union(*dict_list) # explanation B
  }

Explanation:

  • The whole thing inside {} is a dictionary comprehension
  • Explanation A: Go through all elements in dictionary list and get values for current key k if the current dictionary (d) being evaluated actually has that key.

OBS: Without the if k in d expression there could be a bunch of None
values appended to the arrays in case the list of dictionaries
contains different types of keys.

  • Explanation B: gets all keys from list of dictionary and unite them distinctly by using set().union. After all we can only have distinct elements in set data structure.

If you want to do it the traditional way, just go with:

def merge_list_of_dictionaries(dict_list):
  new_dict = {}
  for d in dict_list:
    for d_key in d:
      if d_key not in new_dict:
        new_dict[d_key] = []
      new_dict[d_key].append(d[d_key])
  return new_dict

I think the first solution looks more elegant, but the second one is more legible/readable.

Kind Regards 🙂

Solution 3

I would do this in two steps:

  1. Collect all keys into a single iterable:

    >>> import operator
    >>> from functools import reduce
    >>> all_keys = reduce(operator.or_, (d.keys() for d in foo))
    >>> all_keys
    {'a', 'b', 'c'}
    
  2. Use a dict comprehension to create the desired result:

    >>> bar = {key: [d.get(key) for d in foo] for key in all_keys}
    >>> bar
    {'a': ['x', 'j'], 'b': ['y', None], 'c': ['z', 'z']}
    

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply