-2

For the dictionaries in a list, I need to extract and merge them in a single dictionary without overwriting the existing key values.

For example, I have:

mylist = [{'b': 3}, {'b': 9, 'A': 8, 'Z': 2, 'V': 1}]

The result should be:

{'b': 3, 'A': 8, 'Z': 2, 'V': 1}

Below is my code:

def concatenate_dict(dict_list: list) -> dict:
    final_dict = {}
    for d in dict_list:
        for k, v in d.items():
            if k not in final_dict:
                final_dict |= (k, v)

    return final_dict


mylist = [{'b': 7}, {'b': 10, 'A': 8, 'Z': 2, 'V': 1}]
print(concatenate_dict(mylist))

I do not understand why the "not in" keyword would not skip the existing 'b': 10 item and leave 'b': 7 alone and continue to 'A': 8

azro
  • 53,056
  • 7
  • 34
  • 70
  • 1
    duplicate [How do I merge two dictionaries in a single expression (take union of dictionaries)?](https://stackoverflow.com/questions/38987/how-do-i-merge-two-dictionaries-in-a-single-expression-take-union-of-dictionari) – Robin Dillen Jan 06 '22 at 19:24
  • 5
    Why not call `update` for the dictionaries in reverse order? – mkrieger1 Jan 06 '22 at 19:25
  • 1
    code doesn't compile, you can use `|` with a tuple – azro Jan 06 '22 at 19:26
  • 1
    What do you mean by 'why the "not in" keyword would not skip'? The code does not even run, how can you tell if it does or does not skip anything? – mkrieger1 Jan 06 '22 at 19:29
  • 1
    Is the order important? If not, it makes the problem a lot simpler. – wjandrea Jan 06 '22 at 19:31

3 Answers3

2

Instead of iterating over every dictionary, how about reverse mylist and iteratively update an output dictionary? Then every key-value pair inserted into out from the back will be updated from the front if a key already exists.

out = {}
for d in mylist[::-1]:
    out.update(d)

Output:

{'b': 3, 'A': 8, 'Z': 2, 'V': 1}
0

Fix

Use the appropriate operator, you can't use |= with a tuple

def concatenate_dict(dict_list: list) -> dict:
    final_dict = {}
    for d in dict_list:
        for k, v in d.items():
            if k not in final_dict:
                final_dict[k] = v
    return final_dict

Improve

Iterate on the dicts backwards and use dict.update

def concatenate_dict(dict_list: list) -> dict:
    final_dict = {}
    for d in reversed(dict_list):
        final_dict.update(d)
    return final_dict

Could be with reduce and merge operator

from functools import reduce

def concatenate_dict(dict_list: list) -> dict:
    return reduce(lambda x, y: x | y, reversed(dict_list))
azro
  • 53,056
  • 7
  • 34
  • 70
0

I think the best way to do it, both in terms of readability and efficiency, is to iterate on your dicts in reverse order, as suggested in the Improve section of azro's answer.

However, I'd like to highlight method dict.setdefault, which does exactly what you want: add a key: value to a dict, only if the key wasn't already in the dict.

def concatenate_dict(dict_list: list) -> dict:
    final_dict = {}
    for d in dict_list:
        for k, v in d.items():
            final_dict.setdefault(k, v)
    return final_dict


mylist = [{'b': 7}, {'b': 10, 'A': 8, 'Z': 2, 'V': 1}]
print(concatenate_dict(mylist))
# {'b': 7, 'A': 8, 'Z': 2, 'V': 1}
Stef
  • 13,242
  • 2
  • 17
  • 28