I have two dicts, where the dict inside the dict stands for the values in the other dict:
dict1 = {1:{1,3}, 2:{2}}
dict2 = {1:{5}, 3:{1}}
I am trying to find out, if the combination would result in a loop, for example:
dict1: 1 -> dict2: 3 -> dict1: 1; This would result in a loop, so my script should throw an error.
dict1: 2 -> not in dict2; Not a loop would be okay
dict1: 1 -> dict2: 1 -> 5 not in dict 1; Not a loop would be okay
Any ideas how I could solve that problem? Thanks in advance!
Effectively, your question is about finding a cycle (of any length, if I understand correctly) in a bipartite graph.
With some minor pre-processing, you can use the networkx
package to find if there is any cycle in your graph. networkx
deals with bipartite graphs, but let's just rename out nodes and not need to use the bipartite trait directly.
To pre-process the dictionaries, we add a prefix 'a' to the nodes in the first dict and a prefix 'b' to the nodes in the second (and not forget to add the prefixes to the edge targets):
dict1 = {'a'+str(k): set(map(lambda x: 'b'+str(x), v)) for k, v in dict1.items()}
dict2 = {'b'+str(k): set(map(lambda x: 'a'+str(x), v)) for k, v in dict2.items()}
Now our dictionaries look like this:
{'a1': {'b3', 'b1'}, 'a2': {'b2'}, 'b1': {'a5'}, 'b3': {'a1'}}
{'b1': {'a5'}, 'b3': {'a1'}}
We merge them together to create a single dictionary:
dict3 = dict1
dict3.update(dict2)
And turn that dictionary into a (directed!) graph:
import networkx as nx
g = nx.DiGraph(dict3)
If you're so inclined, you can draw the network (with nx.draw_networkx(g)
) to see what came out:
Well, we can see the cycle between 'a1' and 'b3'. To find them automatically - and this is the point of this answer - we can just use the following command:
nx.simple_cycles(g)
which in this case returns a generator object which yields the cycles (in this case, (list(nx.simple_cycles(g))
is [['b3', 'a1']]
.
But you don't want the whole list; you just want your code to throw an exception if the list is not empty. So, you can use:
assert(not(next(nx.simple_cycles(g), None))
And you're done!