0

I created a class Person and a HashSet. If I add the same person to the HashSet, it is not aware the Person is already present and it will add the same person multiple times. What function do I need to overwrite to have only unique elements in the HashSet?

public class Person
{
    public Person(int age, string name)
    {
        this.age = age;
        this.name = name;
    }

    int age;
    string name;

    public int Age {
        get { return age; }
        set { age = value; }
    }

    public string Name {
        get { return name; }
        set { name = value; }
    }

    public override bool Equals(object obj)
    { 
        var other = obj as Person;
        if (other == null) {
            return false;
        }

        return age == other.age && name == other.name;
    }
}

void Button1Click(object sender, EventArgs e)
{
    List<Person> allPeople = new List<Person>();
    Person p = new Person(15, "John");
    allPeople.Add(p);
    p = new Person(22, "Michael");
    allPeople.Add(p);
    p = new Person(16, "Alex");
    allPeople.Add(p);
    p = new Person(22, "Michael");
    allPeople.Add(p);
    p = new Person(15, "John");
    allPeople.Add(p);

    HashSet<Person> hashset = new HashSet<Person>();

    foreach(Person pers in allPeople) {
        hashset.Add(pers);
    }

    foreach(Person pers in hashset) {
        listBox1.Items.Add(pers.Name + ", " + pers.Age);
    }
}
Nick_F
  • 1,103
  • 2
  • 13
  • 30

1 Answers1

1

First, how does a HashSet know 2 Objects are Equal. It does not ONLY use the "Equals" method for that. It compares two Objects HashCode by using the "GetHashCode" Method on top of that.

So what you need to do is override GetHashCode and find some way to map your Person to a int value.

you could for instance do "age + AsciiValue(name)".

So all you need to do is add

public override int GetHashCode()
{
    return age + AsciiValue(name); //i will leave the ascii value implementation to you
}

to your person class and the duplicate persons should no longer exist in the same HashSet

OP's Implementation:

int AsciiCode(string str) { 
    int sum = 0;
    int len = str.Length;
    for(int i = 0; i < len; i++) {
        sum += str[i] * Convert.ToInt32(Math.Pow(2, i));
        sum = sum % (Convert.ToInt32(Math.Pow(2, 31) - 1));
    } 
    return sum;
}
Alan
  • 949
  • 8
  • 26
  • 1
    The first sentence is incorrect. HashSet does use equals, but only after it has confirmed the hash codes are the same. It is possible to have two objects that are not equal, but have same hash code. – Euphoric Sep 18 '19 at 10:09
  • wait a second, check the sentence again. it doesnt look wrong to me. it does not ONLY use equals – Alan Sep 18 '19 at 10:10
  • Yeah, sorry. I was confused by all-caps NOT to miss the tiny "only" afterwards. Maybe reword the sentence to make it less confusing. – Euphoric Sep 18 '19 at 10:11
  • Thanks, I will multiply the ASCII codes of the characters in name by 2^position and return some large modulo of it. – Nick_F Sep 18 '19 at 10:18
  • int AsciiCode(string str) { int sum = 0; int len = str.Length; for(int i = 0; i < len; i++) { sum += str[i] * Convert.ToInt32(Math.Pow(2, i)); sum = sum % (Convert.ToInt32(Math.Pow(2, 31) - 1)); } return sum; } – Nick_F Sep 18 '19 at 10:29
  • I found a simpler way to override GetHashCode(): public override int GetHashCode() { return new { age, name }.GetHashCode(); } – Nick_F Sep 18 '19 at 11:24