9

There are two dictionaries

x={1:['a','b','c']}
y={1:['d','e','f'],2:['g']}

I want another dictionary z which is a merged one of x and y such that

z = {1:['a','b','c','d','e','f'],2:['g']}

Is it possible to do this operation? I tried update operation

x.update(y)

But it gives me the following result

z= {1:['d','e','f'],2:['g']}
halfer
  • 19,824
  • 17
  • 99
  • 186
athira
  • 167
  • 1
  • 2
  • 10

6 Answers6

8

One line solution:

{ key:x.get(key,[])+y.get(key,[]) for key in set(list(x.keys())+list(y.keys())) }

Example 1:

x={1:['a','b','c']}
y={1:['d','e','f'],2:['g']}
{ key:x.get(key,[])+y.get(key,[]) for key in set(list(x.keys())+list(y.keys())) }

Output:

{1: ['a', 'b', 'c', 'd', 'e', 'f'], 2: ['g']}

Example 2:

one = {'a': [1, 2], 'c': [5, 6], 'b': [3, 4]}
two = {'a': [2.4, 3.4], 'c': [5.6, 7.6], 'd': [3.5, 4.5]}
{ key:one.get(key,[])+two.get(key,[]) for key in set(list(one.keys())+list(two.keys())) }

Output:

{'a': [1, 2, 2.4, 3.4], 'b': [3, 4], 'c': [5, 6, 5.6, 7.6], 'd': [3.5, 4.5]}

3
for k, v in x.items():
if k in y.keys():
    y[k] += v
else:
    y[k] = v

Loop through dictionary getting keys and values, check if the key already exists, in which case append, else add new key with values. It won't work if your values are mixed data types that aren't lists, like you have.

   x={1:['a','b','c'], 3:['y']} 
.. y={1:['d','e','f'],2:['g']} 
..  
..  
.. for k, v in x.items(): 
..     if k in y.keys(): 
..         y[k] += v 
..     else: 
..         y[k] = v 
..      
.. print y
{1: ['d', 'e', 'f', 'a', 'b', 'c'], 2: ['g'], 3: ['y']}
NotAnAmbiTurner
  • 2,553
  • 2
  • 21
  • 44
2

You could do this:

final = {}
dicts = [x,y]  # x and y are each dicts defined by op

for D in dicts:
    for key, value in D.items():  # in python 2 use D.iteritems() instead
        final[key] = final.get(key,[]).extend(value)

final.get(key,[]) will get the value in final for that key if it exists, otherwise it'll be an empty list. .extend(value) will extend that list, empty or not, with the corresponding value in D, which is x or y in this case.

fantabolous
  • 21,470
  • 7
  • 54
  • 51
El'endia Starman
  • 2,204
  • 21
  • 35
1

This is what worked for me :

d1={'a':[1,2,3], 'b':[4,5,6], 'c':[7,8,9]}
d2 = {'a':[10,11,12], 'b':[13,14,15], 'c':[16,17,18]}
d3 = {}
for k in d1.keys():
    d3.update( {k : []} )
    for i in d1[k]:
        d3[k].append(i)
    for j in d2[k]:
        d3[k].append(j)
print(d3)

I know it's a roundabout way of doing it, but the other methods didn't work when the dictionary values were ndarrays.

ikru488
  • 11
  • 1
0

Here is a Python 3 solution for an arbitrary number of dictionaries:

def dict_merge(*dicts_list):
    result = {}
    for d in dicts_list:
        for k, v in d.items():
            result.setdefault(k, []).append(v)
    return result

Note that this solution may create lists with duplicate values. If you need unique values, use set():

def dict_merge(*dicts_list):
    result = {}
    for d in dicts_list:
        for k, v in d.items():
            result.setdefault(k, set()).add(v)
    return result
pmsoltani
  • 976
  • 8
  • 13
-2

If you choose Python2.7 in your project. Counter() can be used in this case:

Python 2.7.16 (default, Jun  5 2020, 22:59:21) 
[GCC 4.2.1 Compatible Apple LLVM 11.0.3 (clang-1103.0.29.20) (-macos10.15-objc- on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> x={1:['a','b','c']}
>>> y={1:['d','e','f'],2:['g']}
>>> from collections import Counter
>>> Counter(x) + Counter(y)
Counter({2: ['g'], 1: ['a', 'b', 'c', 'd', 'e', 'f']})

In Python 3.x, what if you run the same code, you will see:

Python 3.9.0 (v3.9.0:9cf6752276, Oct  5 2020, 11:29:23) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: x={1:['a','b','c']}

In [2]: y={1:['d','e','f'],2:['g']}

In [3]: from collections import Counter

In [4]: Counter(x) + Counter(y)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-0aa8b00837b3> in <module>
----> 1 Counter(x) + Counter(y)

/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py in __add__(self, other)
    759         for elem, count in self.items():
    760             newcount = count + other[elem]
--> 761             if newcount > 0:
    762                 result[elem] = newcount
    763         for elem, count in other.items():

TypeError: '>' not supported between instances of 'list' and 'int'

Let's take a look at the source code at vim /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py +761

To check the different between Python2.x and Python3.x, we will find the path of collections in python2. to do that just simply execute a wrong call like:

>>> Counter(9,1) # wrong way to call.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 475, in __init__
    raise TypeError('expected at most 1 arguments, got %d' % len(args))
TypeError: expected at most 1 arguments, got 2

and then, you see /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py.

Okay, now open both files and locate to the __add__ function in class Counter.

vim -d /Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py +761 /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py

But we could find the deferent in this snipe code.

enter image description here

Think about this, you can see the TypeError: '>' not supported between instances of 'list' and 'int' show two important things:

  • > reflect to def __gt__(self, value, /) method in class dict. so let's check the different between python2 and python3 dict.
  • 'list' and 'int'. to make sure we meet the same type here, just add a line to print it out. before do compare line if newcount > 0: like this way:
print("newcount is --> ", newcount, type(newcount))
if newcount > 0:

and you will see this:

enter image description here

Not surprise, right? we could compare list to int, em makes sense..

let's quickly compare a list with int in python 2.

enter image description here It's returning a True. keep dived into the Python3.x

enter image description here

Okay, now you should be clear about what's going on. to fix this, should be easily do some change on your own python env or commit it to git. enter image description here

Finally, you got two good news, you fix the Python3.x bug. and you got your result.

enter image description here

If desired result is a dict. You can use the following:

z = dict(Counter(x) + Counter(y))
Frank AK
  • 1,705
  • 15
  • 28
nitishagar
  • 9,038
  • 3
  • 28
  • 40