Task: Set consolidation



C#: using System;
using System.Linq;
using System.Collections.Generic;

public class SetConsolidation
{
    public static void Main()
    {
        var setCollection1 = new[] {new[] {"A", "B"}, new[] {"C", "D"}};
        var setCollection2 = new[] {new[] {"A", "B"}, new[] {"B", "D"}};
        var setCollection3 = new[] {new[] {"A", "B"}, new[] {"C", "D"}, new[] {"B", "D"}};
        var setCollection4 = new[] {new[] {"H", "I", "K"}, new[] {"A", "B"}, new[] {"C", "D"},
            new[] {"D", "B"}, new[] {"F", "G", "H"}};
        var input = new[] {setCollection1, setCollection2, setCollection3, setCollection4};
        
        foreach (var sets in input) {
            Console.WriteLine("Start sets:");
            Console.WriteLine(string.Join(", ", sets.Select(s => "{" + string.Join(", ", s) + "}")));
            Console.WriteLine("Sets consolidated using Nodes:");
            Console.WriteLine(string.Join(", ", ConsolidateSets1(sets).Select(s => "{" + string.Join(", ", s) + "}")));
            Console.WriteLine("Sets consolidated using Set operations:");
            Console.WriteLine(string.Join(", ", ConsolidateSets2(sets).Select(s => "{" + string.Join(", ", s) + "}")));
            Console.WriteLine();
        }
    }
    
    
    
    
    
    private static IEnumerable<IEnumerable<T>> ConsolidateSets1<T>(IEnumerable<IEnumerable<T>> sets,
        IEqualityComparer<T> comparer = null)
    {
        if (comparer == null) comparer = EqualityComparer<T>.Default;
        var elements = new Dictionary<T, Node<T>>();
        foreach (var set in sets) {
            Node<T> top = null;
            foreach (T value in set) {
                Node<T> element;
                if (elements.TryGetValue(value, out element)) {
                    if (top != null) {
                        var newTop = element.FindTop();
                        top.Parent = newTop;
                        element.Parent = newTop;
                        top = newTop;
                    } else {
                        top = element.FindTop();
                    }
                } else {
                    elements.Add(value, element = new Node<T>(value));
                    if (top == null) top = element;
                    else element.Parent = top;
                }
            }
        }
        foreach (var g in elements.Values.GroupBy(element => element.FindTop().Value))
            yield return g.Select(e => e.Value);
    }
    
    private class Node<T>
    {
        public Node(T value, Node<T> parent = null) {
            Value = value;
            Parent = parent ?? this;
        }
        
        public T Value { get; }
        public Node<T> Parent { get; set; }
        
        public Node<T> FindTop() {
            var top = this;
            while (top != top.Parent) top = top.Parent;
            
            var element = this;
            while (element.Parent != top) {
                var parent = element.Parent;
                element.Parent = top;
                element = parent;
            }
            return top;
        }
    }
    
    
    
    
    
    private static IEnumerable<IEnumerable<T>> ConsolidateSets2<T>(IEnumerable<IEnumerable<T>> sets,
        IEqualityComparer<T> comparer = null)
    {
        if (comparer == null) comparer = EqualityComparer<T>.Default;
        var currentSets = sets.Select(s => new HashSet<T>(s)).ToList();
        int previousSize;
        do {
            previousSize = currentSets.Count;
            for (int i = 0; i < currentSets.Count - 1; i++) {
                for (int j = currentSets.Count - 1; j > i; j--) {
                    if (currentSets[i].Overlaps(currentSets[j])) {
                        currentSets[i].UnionWith(currentSets[j]);
                        currentSets.RemoveAt(j);
                    }
                }
            }
        } while (previousSize > currentSets.Count);
        foreach (var set in currentSets) yield return set.Select(value => value);
    }
}






VB: Private Function has_intersection(set1 As Collection, set2 As Collection) As Boolean
    For Each element In set1
        On Error Resume Next
        tmp = set2(element)
        If tmp = element Then
            has_intersection = True
            Exit Function
        End If
    Next element
End Function
Private Sub union(set1 As Collection, set2 As Collection)
    For Each element In set2
        On Error Resume Next
        tmp = set1(element)
        If tmp <> element Then
            set1.Add element, element
        End If
    Next element
End Sub
Private Function consolidate(sets As Collection) As Collection
    For i = sets.Count To 1 Step -1
        For j = sets.Count To i + 1 Step -1
            If has_intersection(sets(i), sets(j)) Then
                union sets(i), sets(j)
                sets.Remove j
            End If
        Next j
    Next i
    Set consolidate = sets
End Function
Private Function mc(s As Variant) As Collection
    Dim res As New Collection
    For i = 1 To Len(s)
        res.Add Mid(s, i, 1), Mid(s, i, 1)
    Next i
    Set mc = res
End Function
Private Function ms(t As Variant) As Collection
    Dim res As New Collection
    Dim element As Collection
    For i = LBound(t) To UBound(t)
        Set element = t(i)
        res.Add t(i)
    Next i
    Set ms = res
End Function
Private Sub show(x As Collection)
    Dim t() As String
    Dim u() As String
    ReDim t(1 To x.Count)
    For i = 1 To x.Count
        ReDim u(1 To x(i).Count)
        For j = 1 To x(i).Count
            u(j) = x(i)(j)
        Next j
        t(i) = "{" & Join(u, ", ") & "}"
    Next i
    Debug.Print "{" & Join(t, ", ") & "}"
End Sub
Public Sub main()
    show consolidate(ms(Array(mc("AB"), mc("CD"))))
    show consolidate(ms(Array(mc("AB"), mc("BD"))))
    show consolidate(ms(Array(mc("AB"), mc("CD"), mc("DB"))))
    show consolidate(ms(Array(mc("HIK"), mc("AB"), mc("CD"), mc("DB"), mc("FGH"))))
End Sub