# Find sets of disjoint sets from a list of tuples or sets in python

Posted on

### Question :

Find sets of disjoint sets from a list of tuples or sets in python

here is the problem: I have a list of tuples (could be sets as well if needed). For instance:

``````a = [(1, 5), (4, 2), (4, 3), (5, 4), (6, 3), (7, 6)]
``````

What I want to find is a list

``````r = [(1, 5, 4, 2, 3, 6, 7)]
``````

because the intersection is not empty once all the sets are put together.

For the example

``````a = [(1, 5), (4, 2), (4, 3), (5, 4), (6, 3), (7, 6), (8, 9)]
``````

the result should be

``````r = [(1, 5, 4, 2, 3, 6, 7), (8, 9)]
``````

Hope the problem is clear. So what is the most elegant way to do this in python, if any?

Cheers

These are the connected components of a graph, and can be found using a graphing library such as `networkx`. For your second example:

``````>>> edges = [(1, 5), (4, 2), (4, 3), (5, 4), (6, 3), (7, 6), (8, 9)]
>>> graph = nx.Graph(edges)
>>> [tuple(c) for c in nx.connected_components(graph)]
[(1, 2, 3, 4, 5, 6, 7), (8, 9)]
``````

Take a look at this implementation, it’s fast because it’s using Disjoint set with path compression, both find and merge operations are log(n):

``````class DisjointSet(object):

def __init__(self,size=None):
if size is None:
self.group = {}  # maps a group leader to the group (which is a set)
self.oldgroup = {}
else:
self.group = { i:set([i]) for i in range(0,size) }
self.leader = { i:i for i in range(0,size) }
self.oldgroup = { i:set([i]) for i in range(0,size) }
self.oldleader = { i:i for i in range(0,size) }

self.oldgroup = self.group.copy()
return  # nothing to do
if len(groupa) < len(groupb):
groupa |= groupb
for k in groupb:
else:
else:
else:
self.group[a] = set([a, b])

def connected(self, a, b):
else:
return False
else:
return False

def undo(self):
self.group = self.oldgroup.copy()

def test():
x = DisjointSet()
x.undo()
print x.group

if __name__ == "__main__":
test()
``````

You can also undo the last add. In your case you can do the following:

``````import DisjointSet
a = [(1, 5), (4, 2), (4, 3), (5, 4), (6, 3), (7, 6)]
d = DisjointSet()
for e in a:
print d.group
``````

``````def pairs_to_whole(touching_pairs:list):
out = []
while len(touching_pairs)>0:
first, *rest = touching_pairs
first = set(first)

lf = -1
while len(first)>lf:
lf = len(first)

rest2 = []
for r in rest:
if len(first.intersection(set(r)))>0:
first |= set(r)
else:
rest2.append(r)
rest = rest2

out.append(first)
touching_pairs = rest
return out
``````