Why am I getting two different hashCodes? - c#

This is my code. Why is the hashcode of my two objects not the same?
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
static void Main(string[] args)
{
Person p1 = new Person()
{
Age = 21,
Name = "Anna"
};
Person p2 = new Person()
{
Age = 21,
Name = "Anna"
};
int i = p1.GetHashCode();
int j = p2.GetHashCode();
Console.ReadLine();
}

Since you're not overriding GetHashCode, you'll be using the System.Object version by inheritance.
The GetHashCode method can be overridden by a derived type. If GetHashCode is not overridden, hash codes for reference types are computed by calling the Object.GetHashCode method of the base class, which computes a hash code based on an object's reference
In other words, since they're not the same object instance, they won't have the same hash code.
To make them have the same hash code, you'll have to implement your own GetHashCode by overriding it in the Person class, for example the simple;
public override int GetHashCode ()
{
return Name.GetHashCode () ^ Age.GetHashCode ();
}

Because they are not the same object, just holding the same data.

Related

When would you create an Object from an inherited class?

I'm currently looking into inheritance and polymorphism and I'm a bit confused about where you'd want to create a Person object of type Student?
assuming the following code:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
class Student : Person
{
public int YearOfStudy { get; set; }
public string Course { get; set; }
public string PredictedGrade { get; set; }
}
Now looking online, there are a few options here in terms of creating an object:
Person p = new Person();
Student s = new Student();
Person ps = new Student();
The first objects allows me to set name, age and gender, while the second allows me to set those 3, as well as yearsOfStudy, course and predictedGrade. But I'm unsure of what the third object allows me to do? I can still set all 6 parameters, however I can only use the attributes set in the Person class? Any explanation on the correct usage of the third object would be appreciated.
Thanks
Don't think of this as Person ps = new Student() yet.
The real benefit is being able to abstract common code for all types of Person. So your methods may take in a Person because that's all it needs and will work with any person type you create such as Janitor, Teacher, etc.
var myStudent = new Student()
VerifyAge(myStudent);
VerifyYearOfStudy(myStudent);
public bool VerifyAge(Person person)
{
return person.Age < 200;
}
public bool VerifyYearOfStudy(Student student)
{
return student.YearOfStudy <= DateTime.Now.Year;
}
To clear up some confusion the only time you ever really declare the base in a method is when you want to actually denote that this variable is only meant to be used as that specific type. Think of it as if you had declared your variable using an interface instead. Sure I am working with a Student instance, but I am only working with it as a Person instance or as IPerson.
Normally as a variable in a method you wouldn't do that because pretty much the defacto standard is to just use var for everything nowadays. Where you do make the choice to define Person is normally on properties, method return values, and method parameters. Local variable is not really important.
Because Student class is derived from Person class, any Student object is also a Person object. Thus a notation Person ps = new Student(); means we're declaring variable ps to be of type Person and instantiate it as Student. It could be used if you have a method that takes Person object as parameter, e.g.
public void Foo(Person p) { if(p.Age > 21) Console.WriteLine("OK to drink!"); }
However, if you have a method that operates on properties of derived class you must declare and instantiate the instance of it. So for
public void Foo(Student s) {if(s.YearOfStudy == 1) Console.WriteLine("Freshman"); }
you must use Student s = new Student();.

Loop through two collections to compare for identical collections in C#

I have two collections and I want to loop through each element and compare the corresponding elements in each collection for equality, thus determining if the collections are identical.
Is this possible with a foreach loop or must I use a counter and access the elements by index?
Generally speaking is there a preferred method for comparing collections for equality, like overloading an operator?
TIA.
You can use .SequenceEqual method which is used for this purpose. Read More.
Examples below if link is down or removed for some reason.
Determines whether two sequences are equal by comparing the elements
by using the default equality comparer for their type.
The SequenceEqual(IEnumerable, IEnumerable)
method enumerates the two source sequences in parallel and compares
corresponding elements by using the default equality comparer for
TSource, Default. The default equality comparer, Default, is used to
compare values of the types that implement the IEqualityComparer
generic interface. To compare a custom data type, you need to
implement this interface and provide your own GetHashCode and Equals
methods for the type.
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void SequenceEqualEx1()
{
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
bool equal = pets1.SequenceEqual(pets2);
Console.WriteLine(
"The lists {0} equal.",
equal ? "are" : "are not");
}
/*
This code produces the following output:
The lists are equal.
*/
If you want to compare the actual data of the objects in the sequences
instead of just comparing their references, you have to implement the
IEqualityComparer generic interface in your class. The following
code example shows how to implement this interface in a custom data
type and provide GetHashCode and Equals methods.
public class Product : IEquatable<Product>
{
public string Name { get; set; }
public int Code { get; set; }
public bool Equals(Product other)
{
//Check whether the compared object is null.
if (Object.ReferenceEquals(other, null)) return false;
//Check whether the compared object references the same data.
if (Object.ReferenceEquals(this, other)) return true;
//Check whether the products' properties are equal.
return Code.Equals(other.Code) && Name.Equals(other.Name);
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
int hashProductName = Name == null ? 0 : Name.GetHashCode();
//Get hash code for the Code field.
int hashProductCode = Code.GetHashCode();
//Calculate the hash code for the product.
return hashProductName ^ hashProductCode;
}
}
Usage:
Product[] storeA = { new Product { Name = "apple", Code = 9 },
new Product { Name = "orange", Code = 4 } };
Product[] storeB = { new Product { Name = "apple", Code = 9 },
new Product { Name = "orange", Code = 4 } };
bool equalAB = storeA.SequenceEqual(storeB);
Console.WriteLine("Equal? " + equalAB);
/*
This code produces the following output:
Equal? True
*/

Benefits of using IEquatable

I've been researching IEqualityComparer and IEquitable.
From posts such as What is the difference between IEqualityComparer<T> and IEquatable<T>? the difference between the two is now clear. "IEqualityComparer is an interface for an object that performs the comparison on two objects of the type T."
Following the example at https://msdn.microsoft.com/en-us/library/ms132151(v=vs.110).aspx the purpose of IEqualityComparer is clear and simple.
I've followed the example at https://dotnetcodr.com/2015/05/05/implementing-the-iequatable-of-t-interface-for-object-equality-with-c-net/ to work out how to use it and I get the following code:
class clsIEquitable
{
public static void mainLaunch()
{
Person personOne = new Person() { Age = 6, Name = "Eva", Id = 1 };
Person personTwo = new Person() { Age = 7, Name = "Eva", Id = 1 };
//If Person didn't inherit from IEquatable, equals would point to different points in memory.
//This means this would be false as both objects are stored in different locations
//By using IEquatable on class it compares the objects directly
bool p = personOne.Equals(personTwo);
bool o = personOne.Id == personTwo.Id;
//Here is trying to compare and Object type with Person type and would return false.
//To ensure this works we added an overrides on the object equals method and it now works
object personThree = new Person() { Age = 7, Name = "Eva", Id = 1 };
bool p2 = personOne.Equals(personThree);
Console.WriteLine("Equatable Check", p.ToString());
}
}
public class Person : IEquatable<Person>
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Equals(Person other)
{
if (other == null) return false;
return Id == other.Id;
}
//These are to support creating an object and comparing it to person rather than comparing person to person
public override bool Equals(object obj)
{
if (obj is Person)
{
Person p = (Person)obj;
return Equals(p);
}
return false;
}
public override int GetHashCode()
{
return Id;
}
}
My question is WHY would I use it? It seems like a lot of extra code to the simple version below (bool o):
//By using IEquatable on class it compares the objects directly
bool p = personOne.Equals(personTwo);
bool o = personOne.Id == personTwo.Id;
IEquatable<T> is used by generic collections to determine equality.
From this msdn article https://msdn.microsoft.com/en-us/library/ms131187.aspx
The IEquatable interface is used by generic collection objects such as Dictionary, List, and LinkedList when testing for equality in such methods as Contains, IndexOf, LastIndexOf, and Remove. It should be implemented for any object that might be stored in a generic collection.
This provides an added benefit when using structs, since calling the IEquatable<T> equals method does not box the struct like calling the base object equals method would.

How does HashSet compare elements for equality?

I have a class that is IComparable:
public class a : IComparable
{
public int Id { get; set; }
public string Name { get; set; }
public a(int id)
{
this.Id = id;
}
public int CompareTo(object obj)
{
return this.Id.CompareTo(((a)obj).Id);
}
}
When I add a list of object of this class to a hash set:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(a1);
Everything is fine and ha.count is 2, but:
a a1 = new a(1);
a a2 = new a(2);
HashSet<a> ha = new HashSet<a>();
ha.add(a1);
ha.add(a2);
ha.add(new a(1));
Now ha.count is 3.
Why doesn't HashSet respect a's CompareTo method.
Is HashSet the best way to have a list of unique objects?
It uses an IEqualityComparer<T> (EqualityComparer<T>.Default unless you specify a different one on construction).
When you add an element to the set, it will find the hash code using IEqualityComparer<T>.GetHashCode, and store both the hash code and the element (after checking whether the element is already in the set, of course).
To look an element up, it will first use the IEqualityComparer<T>.GetHashCode to find the hash code, then for all elements with the same hash code, it will use IEqualityComparer<T>.Equals to compare for actual equality.
That means you have two options:
Pass a custom IEqualityComparer<T> into the constructor. This is the best option if you can't modify the T itself, or if you want a non-default equality relation (e.g. "all users with a negative user ID are considered equal"). This is almost never implemented on the type itself (i.e. Foo doesn't implement IEqualityComparer<Foo>) but in a separate type which is only used for comparisons.
Implement equality in the type itself, by overriding GetHashCode and Equals(object). Ideally, implement IEquatable<T> in the type as well, particularly if it's a value type. These methods will be called by the default equality comparer.
Note how none of this is in terms of an ordered comparison - which makes sense, as there are certainly situations where you can easily specify equality but not a total ordering. This is all the same as Dictionary<TKey, TValue>, basically.
If you want a set which uses ordering instead of just equality comparisons, you should use SortedSet<T> from .NET 4 - which allows you to specify an IComparer<T> instead of an IEqualityComparer<T>. This will use IComparer<T>.Compare - which will delegate to IComparable<T>.CompareTo or IComparable.CompareTo if you're using Comparer<T>.Default.
Here's clarification on a part of the answer that's been left unsaid: The object type of your HashSet<T> doesn't have to implement IEqualityComparer<T> but instead just has to override Object.GetHashCode() and Object.Equals(Object obj).
Instead of this:
public class a : IEqualityComparer<a>
{
public int GetHashCode(a obj) { /* Implementation */ }
public bool Equals(a obj1, a obj2) { /* Implementation */ }
}
You do this:
public class a
{
public override int GetHashCode() { /* Implementation */ }
public override bool Equals(object obj) { /* Implementation */ }
}
It is subtle, but this tripped me up for the better part of a day trying to get HashSet to function the way it is intended. And like others have said, HashSet<a> will end up calling a.GetHashCode() and a.Equals(obj) as necessary when working with the set.
HashSet uses Equals and GetHashCode().
CompareTo is for ordered sets.
If you want unique objects, but you don't care about their iteration order, HashSet<T> is typically the best choice.
constructor HashSet receive object what implement IEqualityComparer for adding new object.
if you whant use method in HashSet you nead overrride Equals, GetHashCode
namespace HashSet
{
public class Employe
{
public Employe() {
}
public string Name { get; set; }
public override string ToString() {
return Name;
}
public override bool Equals(object obj) {
return this.Name.Equals(((Employe)obj).Name);
}
public override int GetHashCode() {
return this.Name.GetHashCode();
}
}
class EmployeComparer : IEqualityComparer<Employe>
{
public bool Equals(Employe x, Employe y)
{
return x.Name.Trim().ToLower().Equals(y.Name.Trim().ToLower());
}
public int GetHashCode(Employe obj)
{
return obj.Name.GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
HashSet<Employe> hashSet = new HashSet<Employe>(new EmployeComparer());
hashSet.Add(new Employe() { Name = "Nik" });
hashSet.Add(new Employe() { Name = "Rob" });
hashSet.Add(new Employe() { Name = "Joe" });
Display(hashSet);
hashSet.Add(new Employe() { Name = "Rob" });
Display(hashSet);
HashSet<Employe> hashSetB = new HashSet<Employe>(new EmployeComparer());
hashSetB.Add(new Employe() { Name = "Max" });
hashSetB.Add(new Employe() { Name = "Solomon" });
hashSetB.Add(new Employe() { Name = "Werter" });
hashSetB.Add(new Employe() { Name = "Rob" });
Display(hashSetB);
var union = hashSet.Union<Employe>(hashSetB).ToList();
Display(union);
var inter = hashSet.Intersect<Employe>(hashSetB).ToList();
Display(inter);
var except = hashSet.Except<Employe>(hashSetB).ToList();
Display(except);
Console.ReadKey();
}
static void Display(HashSet<Employe> hashSet)
{
if (hashSet.Count == 0)
{
Console.Write("Collection is Empty");
return;
}
foreach (var item in hashSet)
{
Console.Write("{0}, ", item);
}
Console.Write("\n");
}
static void Display(List<Employe> list)
{
if (list.Count == 0)
{
Console.WriteLine("Collection is Empty");
return;
}
foreach (var item in list)
{
Console.Write("{0}, ", item);
}
Console.Write("\n");
}
}
}
I came here looking for answers, but found that all the answers had too much info or not enough, so here is my answer...
Since you've created a custom class you need to implement GetHashCode and Equals. In this example I will use a class Student instead of a because it's easier to follow and doesn't violate any naming conventions. Here is what the implementations look like:
public override bool Equals(object obj)
{
return obj is Student student && Id == student.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(Id);
}
I stumbled across this article from Microsoft that gives an incredibly easy way to implement these if you're using Visual Studio. In case it's helpful to anyone else, here are complete steps for using a custom data type in a HashSet using Visual Studio:
Given a class Student with 2 simple properties and an initializer
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Student(int id)
{
this.Id = id;
}
}
To Implement IComparable, add : IComparable<Student> like so:
public class Student : IComparable<Student>
You will see a red squiggly appear with an error message saying your class doesn't implement IComparable. Click on suggestions or press Alt+Enter and use the suggestion to implement it.
You will see the method generated. You can then write your own implementation like below:
public int CompareTo(Student student)
{
return this.Id.CompareTo(student.Id);
}
In the above implementation only the Id property is compared, name is ignored. Next right-click in your code and select Quick actions and refactorings, then Generate Equals and GetHashCode
A window will pop up where you can select which properties to use for hashing and even implement IEquitable if you'd like:
Here is the generated code:
public class Student : IComparable<Student>, IEquatable<Student> {
...
public override bool Equals(object obj)
{
return Equals(obj as Student);
}
public bool Equals(Student other)
{
return other != null && Id == other.Id;
}
public override int GetHashCode()
{
return HashCode.Combine(Id);
}
}
Now if you try to add a duplicate item like shown below it will be skipped:
static void Main(string[] args)
{
Student s1 = new Student(1);
Student s2 = new Student(2);
HashSet<Student> hs = new HashSet<Student>();
hs.Add(s1);
hs.Add(s2);
hs.Add(new Student(1)); //will be skipped
hs.Add(new Student(3));
}
You can now use .Contains like so:
for (int i = 0; i <= 4; i++)
{
if (hs.Contains(new Student(i)))
{
Console.WriteLine($#"Set contains student with Id {i}");
}
else
{
Console.WriteLine($#"Set does NOT contain a student with Id {i}");
}
}
Output:

What is a good data structure to use for holding two values?

For example, I have in my application a list of a type what has a persons name as it's name and holds two values. The name of the type is the persons name and the type contains only their age and number of std's.
My first idea was to make a class of Persons with Age and NumStds properties where Age and NumStds is required in the constructor and the create a List which I can add to.
class Person
{
public string Name { get; set; }
public int NumSTDs { get; set; }
public int Age { get; set; }
public Person(string name, int age, int stds)
{
Name = name;
Age = age;
NumSTDs = stds;
}
}
static void Main(string[] args)
{
List<Person> peoples = new List<Person>();
peoples.Add(new Person("Julie", 23, 45));
}
I was just wondering if there is a data structure where I could just refer to the elements in the List<> by their Name and have the properties attached to them come along for the ride. Like I could say
people.Remove(Julie)
It sounds like your are looking for a Dictionary.
Dictionary<string, Person> peoples = new Dictionary<string, Person>();
Person oPerson = new Person("Julie", 23, 45);
peoples.Add(oPerson.Name, oPerson);
Another option is System.Collections.ObjectModel.KeyedCollection. This takes a little more work to implement, but can be useful.
To make this work, create a collection class for person and override the GetKeyForItem method:
public class PersonCollection : System.Collections.ObjectModel.KeyedCollection<string, Person>
{
protected override string GetKeyForItem(Person item)
{
return item.Name;
}
}
Then you can add items to the collection as in your example:
PersonCollection peoples = new PersonCollection();
peoples.Add(new Person("Julie", 23, 45));
Then to remove the item:
peoples.Remove("Julie");
Have a look at the KeyedCollection<TKey, TValue> Class.
KeyedCollection<TKey, TValue> Class
Provides the abstract base class for a collection whose keys are embedded in the values.
You need to derive your own collection class from this abstract class, e.g.
class PersonCollection : KeyedCollection<string, Person>
{
protected override string GetKeyForItem(Person item)
{
return item.Name;
}
}
Example:
static void Main(string[] args)
{
var peoples = new PersonCollection();
var julie = new Person("Julie", 23, 45)
peoples.Add(julie);
people.Remove(julie);
// - or -
people.Remove("Julie");
}
Note that the Name property of your Person class should be immutable (read-only).
I'm not sure of your requirements, but just looking at your Remove() statement at the end of your post, you could get the same effect with a linq expression.
people.Remove(p => string.Compare(p.Name, "Julia", true) == 0);
The problem with using a Dictionary<string, Person> for this is that you can have a key that doesn't match the name of the person. This can be avoided, but I'd rather use a HashSet<Person> for the job. The performance is the same.
You only need to prepare your class by overriding GetHashCode to return the hash code of Name.
public override int GetHashCode()
{
return Name.GetHashCode();
}

Categories