Here is a solution that is 1000 times slower than belisarius
's and is likely to scale terribly. I post it only for the purpose of illustrating that a "transparent" approach can be easily implemented in one line in Mathematica (transparent meaning that the actual steps taken are basically shown, unlike the graph-theoretic function approach, which hides some of the algorithms under the hood; as belisarius
once told me:
The main problem when programming in Mma is finding a way without programming.
which is why their solution is so much better).
input = {{1, 1}, {1, 2}, {1, 3}, {2, 3}, {3, 3}, {4, 4}};
FixedPoint[Union@@@Gather[#, ! DisjointQ[#1, #2] &] &, input]
(* {{1, 2, 3}, {4}} *)
The function Gather[#, ! DisjointQ[#1, #2] &]
separates the list into sublists in which the elements fed pairwise to the function ! DisjointQ[#1, #2] &
yield True
. For instance,
! DisjointQ[#1, #2] & @@ {{1, 1}, {1, 2}}
! DisjointQ[#1, #2] & @@ {{1, 1}, {4, 4}}
(* True *)
(* False *)
On a single pass, he function Gather
won't collect all the pairs together that need to be paired:
Gather[#, ! DisjointQ[#1, #2] &] & @ inputs
(* {{{1, 1}, {1, 2}, {1, 3}}, {{2, 3}, {3, 3}}, {{4, 4}}} *)
For this reason, we Apply
Union
to each of the sublists and try again:
Union@@@Gather[#, ! DisjointQ[#1, #2] &] & @ inputs
Union@@@Gather[#, ! DisjointQ[#1, #2] &] & @ %
(* {{1, 2, 3}, {2, 3}, {4}} *)
(* {{1, 2, 3}, {4}} *)
On longer lists with more than two connected components, it is likely that this will need to be run more than twice, which is why I employ FixedPointList
to iteratively run Union@@@Gather[#, ! DisjointQ[#1, #2] &] &
until all the connected points are gathered together. Part of the slowness of this method has to do with the fact that we run over the list multiple times.
For instance,
input = RandomInteger[{1, 1000}, {1000, 2}];
(* belisarius *)
ConnectedComponents@Graph[UndirectedEdge @@@ input]; // AbsoluteTiming
(* march *)
FixedPoint[Union @@@ Gather[#, ! DisjointQ[#1, #2] &] &, input]; // AbsoluteTiming
(* {0.001302, Null} *)
(* {3.513250, Null} *)