Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compare two HashSets on one property that both share?

Tags:

c#

hashset

I need to compare two hashsets that are of the same type, but have differing values for only some properties. I essentially need a more specific ExceptWith.

I've tried using ExceptWith but that doesn't allow you to specify a property to compare on, as far as I know.

We should pretend that I cannot add or remove any properties to the Person class.

   class Program
{
    private class Person
    {
        public string Name { get; set; }
        public string Id { get; set; }
    }

    static void Main(string[] args)
    {
        var people1 = new[]
        {
            new Person
            {
                Name = "Amos",
                Id = "123"
            },
            new Person
            {
                Name = "Brian",
                Id = "234"
            },
            new Person
            {
                Name = "Chris",
                Id = "345"
            },
            new Person
            {
                Name = "Dan",
                Id = "456"
            }
        };

        var people2 = new[]
        {
            new Person
            {
                Name = "Amos",
                Id = "098"
            },
            new Person
            {
                Name = "Dan",
                Id = "987"
            }
        };

        var hash1 = new HashSet<Person>(people1);

        var hash2 = new HashSet<Person>(people2);

        var hash3 = new HashSet<Person>(); // where hash3 is hash1 without the objects from hash2 solely based on matching names, not caring about Id matching

        foreach (var item in hash3) // should print out Brian, Chris
        {
            Console.WriteLine($"{item.Name}");
        }
    }
}
like image 699
CBeams Avatar asked Jan 31 '26 06:01

CBeams


2 Answers

In your Person class, you should define your own GetHashCode method, so that it only uses the person's name and not the ID.

If you do that, you also have to define your own Equals method: Why is it important to override GetHashCode when Equals method is overridden?

like image 179
miara Avatar answered Feb 01 '26 19:02

miara


You could just hash the names from the second array to use in a Linq filter to create the final HashSet

var excludeName = new HashSet<string>(people2.Select(x => x.Name));
var hash3 = new HasSet<Person>(people1.Where(x => !exludeName.Contains(x.Name));

This can be especially useful if that list of values to exclude is very large as it will make the entire process run in linear time.

Or here's how you can set up the HashSets with IEqualityComparer<T>.

public class PersonByNameComparer : IEqualityComparer<Peron>
{
    public bool Equals(Person p1, Persion p2)
    {
        return p1.Name == p2.Name;
    }

    public int GetHashCode(Person p)
    {
        return p.Name.GetHashCode();
    }
}

Note: This means that the HashSets cannot contain two items with the same Name even if the Id is different. But it also means it cannot contain to different objects with the same values like your current setup.

And then uses it like this.

var comparer = new PersonByNameComparer();

var hash1 = new HashSet<Person>(people1, comparer);
var hash2 = new HashSet<Person>(people2, comparer);

// Note that ExceptWith will mutate the existing hash.  
hash1.ExceptWith(hash2); 

// Alternatively you can create the new hash like this
var hash3 = new HashSet<Persion>(hash1.Where(p => !hash2.Contains(p)));
like image 36
juharr Avatar answered Feb 01 '26 21:02

juharr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!