Search code examples
c#compiler-errorshashsetintersect

Intersect on HashSet results in compile error


I've been trying to write a program, in which I want to use the intersection of two HashSets. Therefore I wrote the following code (for test purposes):

HashSet<int> test1 = new HashSet<int>() { 1, 3, 5, 7, 9 };
HashSet<int> test2 = new HashSet<int>() { 1, 2, 3, 4, 5, 6};
HashSet<int> intersect = new HashSet<int>();
intersect = test1.Intersect(test2);

Line 5 shows an error (code CS0266) which - that's C#'s suggestion - can be corrected by change the line to: intersect = (HashSet<int>)test1.Intersect(test2); But when I run the program, the error appears again. I literally have no clue why, even after searching for an answer. I want to achieve a intersection in the mathematical sense, so that the result for the variable intersect should be { 1, 3, 5}. And what I found out - but couldn't test - is, that after using the intersect-method on test1, it changes the list in test1 to the intersection, is that true? If yes, is there any chance to avoid this? In my real program I don't want the variable to change into the intersection.

Should I just make a for-loop with an if-statement, to make my own intersection-method, or does this make the code worse?

As said, I tried to make use of C#'s suggestion, but this doesn't work either. Because I'm a programming-beginner, I'm not really able to understand the definition of the intersect-method (because of this IEnumerable thing...), so I can't solve the problem using existend methods. And because I think my own method could be very inefficient, I don't to it my own. Furthermore I just want to understand, what's the problem. There are two HashSets, both containing integers, which should be intersected and saved in an extra variable...


Solution

  • Intersect() returns a IEnumerable<T>. You can use IntersectWith(), which modifies the current HashSet<T> object to contain only elements that are present in that object and in the specified collection:

    HashSet<int> test1 = new HashSet<int>() { 1, 3, 5, 7, 9 };
    HashSet<int> test2 = new HashSet<int>() { 1, 2, 3, 4, 5, 6};
    test1.IntersectWith(test2); // we are altering test1 here
    // test1 contains now [1, 3, 5]
    

    or use the side-effect free Linq Intersect() to get an IEnumerable<T> and if you want it to be a new HashSet<T> just use a constructor:

    HashSet<int> test1 = new HashSet<int>() { 1, 3, 5, 7, 9 };
    HashSet<int> test2 = new HashSet<int>() { 1, 2, 3, 4, 5, 6};
    HashSet<int> intersect = new HashSet<int>(test1.Intersect(test2));
    // intersect contains now [1, 3, 5]
    

    Remarks (from MSDN)

    If the collection represented by the other parameter is a HashSet<T> collection with the same equality comparer as the current HashSet<T> object, this method is an O(n) operation. Otherwise, this method is an O(n + m) operation, where n is Count and m is the number of elements in other.

    Basically in your case IntersectWith() is going to be more efficient!

    Complete demo:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    
    public class Program
    {
        public static void Main()
        {
            HashSet<int> test1 = new HashSet<int>() {1, 3, 5, 7, 9};
            HashSet<int> test2 = new HashSet<int>() {1, 2, 3, 4, 5, 6};
            HashSet<int> intersect = new HashSet<int>(test1.Intersect(test2));
            intersect.Dump();
            test1.IntersectWith(test2);
            test1.Dump();
        }
    }
    

    Try it Online!