jon_shep
jon_shep

Reputation: 1463

Merging 3 dict()'s in python

Is there a method of logically merging multiple dictionaries if they have common strings between them? Even if these common strings match between values of one dict() to a key of another?

I see a lot of similar questions on SO but none that seem to address my specific issue of relating multiple keys in "lower level files" to those in higher keys/values(level1dict)

Say we have:

level1dict = { '1':[1,3], '2':2 }
level2dict = { '1':4, '3':[5,9], '2':10 }
level3dict = { '1':[6,8,11], '4':12, '2':13, '3':[14,15], '5':16, '9':17, '10':[18,19,20]}
finaldict = level1dict

When I say logically I mean, in level1dict 1=1,3 and in level2dict 1=4 and 3=5,9 so overall (so far) 1 = 1,3,4,5,9 (sorting not important)

The result I would like to get to is

#.update or .append or .default?
finaldict = {'1':[1,3,4,5,9,6,8,11,12,14,15,16,17] '2':[2,10,18,19,20]}

Answered: Thank you Ashwini Chaudhary and Abhijit for the networkx module.

Upvotes: 3

Views: 257

Answers (3)

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250961

In [106]: level1dict = { '1':[1,3], '2':2 }

In [107]: level2dict = { '1':4, '3':[5,9], '2':10 }
In [108]: level3dict = { '1':[6,8,11], '4':12, '2':13, '3':[14,15], '5':16, '9':17, '10':[18,19,20]}

In [109]: keys=set(level2dict) & set(level1dict) & set(level3dict) #returns ['1','2']
In [110]: dic={}

In [111]: for key in keys:
    dic[key]=[]
    for x in (level1dict,level2dict,level3dict):
        if isinstance(x[key],int):
            dic[key].append(x[key])
        elif isinstance(x[key],list):
            dic[key].extend(x[key])
   .....:             

In [112]: dic
Out[112]: {'1': [1, 3, 4, 6, 8, 11], '2': [2, 10, 13]}

# now iterate over `dic` again to get the values related to the items present
# in the keys `'1'` and `'2'`.

In [122]: for x in dic:
    for y in dic[x]:
        for z in (level1dict,level2dict,level3dict):
            if str(y) in z and str(y) not in dic:
                if isinstance(z[str(y)],(int,str)):
                     dic[x].append(z[str(y)])
                elif isinstance(z[str(y)],list):
                     dic[x].extend(z[str(y)])
   .....:                     

In [123]: dic
Out[123]: 
{'1': [1, 3, 4, 6, 8, 11, 5, 9, 14, 15, 12, 16, 17],
 '2': [2, 10, 13, 18, 19, 20]}

Upvotes: 2

Abhijit
Abhijit

Reputation: 63737

This is a problem of connected component subgraphs and can be best determined if you want to use networkx. Here is a solution to your problem

>>> import networkx as nx
>>> level1dict = { '1':[1,3], '2':2 }
>>> level2dict = { '1':4, '3':[5,9], '2':10 }
>>> level3dict = { '1':[6,8,11], '4':12, '2':13, '3':[14,15], '5':16, '9':17, '10':[18,19,20]}
>>> G=nx.Graph()
>>> for lvl in level:
    for key, value in lvl.items():
        key = int(key)
        try:
            for node in value:
                G.add_edge(key, node)
        except TypeError:
            G.add_edge(key, value)


>>> for sg in nx.connected_component_subgraphs(G):
    print sg.nodes()


[1, 3, 4, 5, 6, 8, 9, 11, 12, 14, 15, 16, 17]
[2, 10, 13, 18, 19, 20]
>>> 

Here is how you visualize it

>>> import matplotlib.pyplot as plt
>>> nx.draw(G)
>>> plt.show()

enter image description here

Upvotes: 9

Lev Levitsky
Lev Levitsky

Reputation: 65791

A couple of notes:

  1. It's not convenient that some values are numbers and some are lists. Try converting numbers to 1-item lists first.
  2. If the order is not important, you'll be better off using sets instead of lists. They have methods for all sorts of "logical" operations.

Then you can do:

In [1]: dict1 = {'1': {1, 3}, '2': {2}}

In [2]: dict2 = {'1': {4}, '2': {10}, '3': {5, 9}}

In [3]: dict3 = {'1': {6, 8, 11}, '2': {13}, '4': {12}}

In [4]: {k: set.union(*(d[k] for d in (dict1, dict2, dict3)))
    for k in set.intersection(*(set(d.keys()) for d in (dict1, dict2, dict3)))}
Out[4]: {'1': set([1, 3, 4, 6, 8, 11]), '2': set([2, 10, 13])}

Upvotes: 2

Related Questions