简体   繁体   中英

Using union on two lists is not working as expected

I've read about thirty posts on this subject and thought I followed your instructions to the letter.

Here is the class I'm using:

public class UserID
{
    public int user_id { get; set; }
    public bool exists { get; set; }
}

I've created two good lists.

List<UserID> List1 = new List<UserID>();
List<UserID> List2 = new List<UserID>();

I've populated both lists successfully.

I'm trying to get a list of unique user ids. I found the union method for lists and gave it a shot.

List<UserID> ResultList = new List<UserID>();

ResultList = List1.Union(List2).ToList();

Here's the issue. After the last line here runs the ResultList is just the two lists put together.

List1 has { 10, 20, 30, 40 } List2 has { 10, 30, 40, 50, 60 }

I'm expecting the union to give me:

ResultList = { 10, 20, 30, 40, 50, 60 }

but instead it's giving me:

ResultList = { 10, 20, 30, 40, 10, 30, 40, 50, 60 }

What am I doing wrong? I've read a bunch of different posts that all say the same thing - basically the usage. Am I not using it correctly? I'm not getting any errors, it just isn't giving me the union I was expecting.

The problem is that compiler doesn't know how to compare two UserID objects.It uses default equality comparer which compares your object by references.So even though they have same user_id they treated as different because the references are different.

You need to tell the compiler to compare your objects based on user_id property by either overriding Equals and GetHashCode methods in your class or implementing an [ IEqualityComparer ]. 1

Union does remove duplicates (see here ). This is what makes it different to Concat .

However to do so it needs to be enable to compare the items in the two sequences in the way you're expecting (in that two instances of UserId with the internal value set to 10 are equal).

To do so, either provide an equality comparer, or implement IEquatable on the UserId class. The MSDN article has an example of doing this on a Product class.

As Selman22 suggested I needed to use the [IEqualityComparer].

I added this to my code.

public class CompareUserIDs : IEqualityComparer<UserID>
{
    public bool Equals(UserID x, UserID y)
    {
        return x.user_id.Equals(y.user_id);
    }

    public int GetHashCode(UserID obj)
    {
        return obj.user_id.GetHashCode();
    }
}

I then called it as follows:

IntermediateResult = List1.Union(List2).ToList();
IEqualityComparer<UserID> customComparer = new CompareResultTables();
IEnumerable<UserID> myresult = IntermediateResult.Distinct(customComparer);

And voila! I had my, "union". myresult contained only the unique elements from both lists.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM