Why am I not getting results when doing an intersection?

User class:

public class User  
{
    public int ID { get; set; }
    public string Email { get; set; }
}

      

code:

        var usersL = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var usersR = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var both = (from l in usersL select l)
            .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);

      

Which returns 0 results.

I know I can do something like this using join , but I want to use Intersect because A) this will eventually work on some DB of code and we want to use that feature (too long to figure out why) and B) I'm just wondering why Intersect doesn't work here.

        var both = from l in usersL
                   join r in usersR on l.ID equals r.ID
                   select l;

      

+3


source to share


2 answers


.Net provides comparison logic for predefined types. In the case of your join request, you were concatenating (comparing) two identifiers that were of type Int (predefined types)

var both = from l in usersL
           join r in usersR on l.ID equals r.ID
           select l;

      

In the case of your intersection request, you are trying to compare two custom user objects of type User. Hence, you need to provide your own comparison implementation logic.

There are 2 ways to solve this problem ...

Option 1: Implement IEqualityComparer



public class User
{
    public int ID { get; set; }
    public string Email { get; set; }
}

public class MyEqualityComparer : IEqualityComparer<User>
{
    public bool Equals(User x, User y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        return x.ID.Equals(y.ID) &&
               x.Email.Equals(y.Email);
    }

    public int GetHashCode(User u)
    {
        return new { u.ID, u.Email }.GetHashCode();
    }
}

class Program
{
    static void Main(string[] args)
    {

        var usersL = new List<User>()
                    {
                        new User{ID = 1,Email = "abc@foo.com"},
                        new User{ID = 2,Email = "def@foo.com"}
                    };

        var usersR = new List<User>()
                    {
                        new User{ID = 1,Email = "abc@foo.com"},
                        new User{ID = 2,Email = "def@foo.com"}
                    };

        var both =  (from l in usersL select l)
          .Intersect(from users in usersR select users, new MyEqualityComparer());

        foreach (var r in both)
            Console.WriteLine(r.Email);
    }
}

      

Option 2: Override Equals and GetHashcode methods in the custom object itself

public class User 
{
    public int ID { get; set; }
    public string Email { get; set; }

    public override bool Equals(Object obj)
    {
        // Check for null values and compare run-time types.
        if (obj == null || GetType() != obj.GetType())
            return false;

        User x = (User)obj;
        return (ID == x.ID) && (Email == x.Email);
    }

    public override int GetHashCode()
    {
        return new { ID, Email }.GetHashCode();
    }
}

class Program
{
    static void Main(string[] args)
    {

        var usersL = new List<User>()
            {
                new User{ID = 1,Email = "abc@foo.com"},
                new User{ID = 2,Email = "def@foo.com"}
            };

        var usersR = new List<User>()
            {
                new User{ID = 1,Email = "abc@foo.com"},
                new User{ID = 2,Email = "def@foo.com"}
            };

        var both = (from l in usersL select l)
          .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);
    }
}

      

Hope it helps.

+1


source


This is the answer to @sundeep who said "Now for your second question ..." (I wish you could link to the comments). I am just creating a new answer as I don't want to destroy the context of my original question

Custom class that implements IEqualityComparer

public class User : IEqualityComparer<User>
{
    public int ID { get; set; }
    public string Email { get; set; }

    public bool Equals(User x, User y)
    {
        if (object.ReferenceEquals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        return x.ID.Equals(y.ID) &&
               x.Email.Equals(y.Email);
    }

    public int GetHashCode(User obj)
    {
        return new { obj.ID, obj.Email }.GetHashCode();
    }
}

      



Intersection returns no rows:

        var usersL = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var usersR = new List<User>()
                        {
                            new User{ID = 1,Email = "abc@foo.com"},
                            new User{ID = 2,Email = "def@foo.com"}
                        };

        var both = (from l in usersL select l)
            .Intersect(from users in usersR select users);

        foreach (var r in both)
            Console.WriteLine(r.Email);

      

0


source







All Articles