Search code examples
c#disjoint-sets

Check if lists are disjoint


I need to check if two lists have any elements in common. I just need a yes/no - I don't need the actual list of common elements.

I could use Enumerable.Intersect() but this does actually return the set of matching items which seems like it would require extra overhead. Is there a better method for checking if lists are disjoint?


My lists do actually happen to be List<T> but that isn't crucial and I could use something like HashSet (say) if that were more convenient. i.e., I don't want to unnecessarily constrain potential solutions.

Grazie mille


Solution

  • Simplest version (using Intersect):

     public bool Compare(List<T> firstCollection, List<T> secondCollection)
     {
        return firstCollection.Intersect(secondCollection).Any();
     }
    

    Only caveat is either T shall implement IEquatable<T> or pass custom IEqualityComparer<T> in the Intersect call. Also make sure that GetHashCode is overriden along with Equals

    Edit 1:

    This version using Dictionary will not just provide boolean comparison, but also the elements. In this solution Dictionary in the end would contain data related to number of intersecting elements, number of elements in one of the collection but not in another, so fairly durable. This solution also has IEquatable<T> requirement

    public bool CompareUsingDictionary(IEnumerable<T> firstCollection, IEnumerable<T> secondCollection)
        {
            // Implementation needs overiding GetHashCode methods of the object base class in the compared type
            // Obviate initial test cases, if either collection equals null and other doesn't then return false. If both are null then return true.
            if (firstCollection == null && secondCollection != null)
                return false;
            if (firstCollection != null && secondCollection == null)
                return false;
            if (firstCollection == null && secondCollection == null)
                return true;
    
            // Create a dictionary with key as Hashcode and value as number of occurences
            var dictionary = new Dictionary<int, int>();
    
            // If the value exists in first list , increase its count
            foreach (T item in firstCollection)
            {
                // Get Hash for each item in the list
                int hash = item.GetHashCode();
    
                // If dictionary contains key then increment 
                if (dictionary.ContainsKey(hash))
                {
                    dictionary[hash]++;
                }
                else
                {
                    // Initialize he dictionary with value 1
                    dictionary.Add(hash, 1);
                }
            }
    
            // If the value exists in second list , decrease its count
            foreach (T item in secondCollection)
            {
                // Get Hash for each item in the list
                int hash = item.GetHashCode();
    
                // If dictionary contains key then decrement
                if (dictionary.ContainsKey(hash))
                {
                    dictionary[hash]--;
                }
                else
                {
                    return false;
                }
            }
    
            // Check whether any value is 0
            return dictionary.Values.Any(numOfValues => numOfValues == 0);
        }