I'm looking at how build the best HashCode for a class and I see some algorithms. I saw this one : Hash Code implementation, seems to be that .NET classes HashCode methods are similar (see by reflecting the code).
So question is, why don't create the above static class in order to build a HashCode automatically, just by passing fields we consider as a "key".
// Old version, see edit
public static class HashCodeBuilder
{
public static int Hash(params object[] keys)
{
if (object.ReferenceEquals(keys, null))
{
return 0;
}
int num = 42;
checked
{
for (int i = 0, length = keys.Length; i < length; i++)
{
num += 37;
if (object.ReferenceEquals(keys[i], null))
{ }
else if (keys[i].GetType().IsArray)
{
foreach (var item in (IEnumerable)keys[i])
{
num += Hash(item);
}
}
else
{
num += keys[i].GetHashCode();
}
}
}
return num;
}
}
And use it as like this :
// Old version, see edit
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(object.ReferenceEquals(other, null))
? false
: Key1 == other.Key1 && Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Will be much simpler that always is own method, no? I'm missing something?
EDIT
According all remarks, I got the following code :
public static class HashCodeBuilder
{
public static int Hash(params object[] args)
{
if (args == null)
{
return 0;
}
int num = 42;
unchecked
{
foreach(var item in args)
{
if (ReferenceEquals(item, null))
{ }
else if (item.GetType().IsArray)
{
foreach (var subItem in (IEnumerable)item)
{
num = num * 37 + Hash(subItem);
}
}
else
{
num = num * 37 + item.GetHashCode();
}
}
}
return num;
}
}
public sealed class A : IEquatable<A>
{
public A()
{ }
public string Key1 { get; set; }
public string Key2 { get; set; }
public string Value { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as A);
}
public bool Equals(A other)
{
if(ReferenceEquals(other, null))
{
return false;
}
else if(ReferenceEquals(this, other))
{
return true;
}
return Key1 == other.Key1
&& Key2 == other.Key2;
}
public override int GetHashCode()
{
return HashCodeBuilder.Hash(Key1, Key2);
}
}
Your Equals method is broken - it's assuming that two objects with the same hash code are necessarily equal. That's simply not the case.
Your hash code method looked okay at a quick glance, but could actually do some with some work - see below. It means boxing any value type values and creating an array any time you call it, but other than that it's okay (as SLaks pointed out, there are some issues around the collection handling). You might want to consider writing some generic overloads which would avoid those performance penalties for common cases (1, 2, 3 or 4 arguments, perhaps). You might also want to use a foreach loop instead of a plain for loop, just to be idiomatic.
You could do the same sort of thing for equality, but it would be slightly harder and messier.
EDIT: For the hash code itself, you're only ever adding values. I suspect you were trying to do this sort of thing:
int hash = 17;
hash = hash * 31 + firstValue.GetHashCode();
hash = hash * 31 + secondValue.GetHashCode();
hash = hash * 31 + thirdValue.GetHashCode();
return hash;
But that multiplies the hash by 31, it doesn't add 31. Currently your hash code will always return the same for the same values, whether or not they're in the same order, which isn't ideal.
EDIT: It seems there's some confusion over what hash codes are used for. I suggest that anyone who isn't sure reads the documentation for Object.GetHashCode and then Eric Lippert's blog post about hashing and equality.
This is what I'm using:
public static class ObjectExtensions
{
/// <summary>
/// Simplifies correctly calculating hash codes based upon
/// Jon Skeet's answer here
/// http://stackoverflow.com/a/263416
/// </summary>
/// <param name="obj"></param>
/// <param name="memberThunks">Thunks that return all the members upon which
/// the hash code should depend.</param>
/// <returns></returns>
public static int CalculateHashCode(this object obj, params Func<object>[] memberThunks)
{
// Overflow is okay; just wrap around
unchecked
{
int hash = 5;
foreach (var member in memberThunks)
hash = hash * 29 + member().GetHashCode();
return hash;
}
}
}
Example usage:
public class Exhibit
{
public virtual Document Document { get; set; }
public virtual ExhibitType ExhibitType { get; set; }
#region System.Object
public override bool Equals(object obj)
{
return Equals(obj as Exhibit);
}
public bool Equals(Exhibit other)
{
return other != null &&
Document.Equals(other.Document) &&
ExhibitType.Equals(other.ExhibitType);
}
public override int GetHashCode()
{
return this.CalculateHashCode(
() => Document,
() => ExhibitType);
}
#endregion
}
Instead of calling keys[i].GetType().IsArray, you should try to cast it to IEnumerable (using the as keyword).
You can fix the Equals method without repeating the field list by registering a static list of fields, like I do here using a collection of delegates.
This also avoids the array allocation per-call.
Note, however, that my code doesn't handle collection properties.
Related
I have a class named accessoire :
class accessoire
{
public int value1 { get; set; }
public string Value2 { get; set; }
}
then i have a List of that product
List<accessoire> accessoires
And i have an UI where the user pick the product he wants from a DataGridview and when he selected it launch an event that add this item to the list :
private void ProductBrowser_OnItemAdded(Accessoire item)
{
if (Cart.Contains(item))
{
MessageBox.Show("Produit deja ajoutée au panier ! ");
}
else
{
Cart.Add(item);
ProductView.Rows.Add(item.Ref, item.Name, Function.CatName(item.Cat), item.SellPrice, "1", Convert.ToDouble(item.SellPrice) * Convert.ToDouble(item.QtetoSell));
TotalPriceSet();
MessageBox.Show("Produit Ajouté !");
}
}
this doesnt work , but when i change it to :
private void ProductBrowser_OnItemAdded(Accessoire item)
{
var InList = Cart.Find(product => product.Ref == item.Ref);
if (Cart.Contains(InList))
{
MessageBox.Show("Product already in list ! ");
}
else
{
Cart.Add(item);
ProductView.Rows.Add(item.Ref, item.Name, Function.CatName(item.Cat), item.SellPrice, "1", Convert.ToDouble(item.SellPrice) * Convert.ToDouble(item.QtetoSell));
TotalPriceSet();
MessageBox.Show("product added !");
}
}
it works , but i'am still wondering why the first code doesnt work it keep adding that item to the list ? in other way how does the method .Contains()works ? what does it check to know if the item is or the list on not ?
The reason it doesn't find the object in the list is because it is a reference comparison, comparing the instances of the object, not the values. You can have two instances of your class with the same values in their properties, but if you compare them, they are not equal:
accessoire item1 = new accessoire();
item1.value1 = 1;
item1.value2 = "one";
accessoire item2 = new accessoire();
item2.value1 = 1;
item2.value2 = "one";
if(item1 == item2) MessageBox.Show("Same");
else MessageBox.Show("Different");
When you select the item from the list to compare with, you are pulling the specific instance, which does exist in the list.
You need to implement the Equals method of accessoire to properly compare all properties/fields in it. The default implementation of Equals uses ReferenceEquals, which only works if the two instances are in fact the same.
if (Cart.Contains(item))
is matching by equality.
If object.Equals(T) is not satisified, it will fail. That means the smallest change, even whitespace in a string, will return false. You'll also get a false result if you have two instances of the same class. Contains must refer to exactly item.
var InList = Cart.Find(product => product.Ref == item.Ref) is a match by property. This means that other properties of the product/item can all be different, as long as .Ref matches. I presume Ref is a primary key, which is why you're not getting problems in your result where Find() returns the wrong item.
You can get around the difference by overriding Equals for Cart, but I don't recommend it. It can make debugging hell later.
Just implement the equals method
// override object.Equals
public override bool Equals(object obj)
{
//
// See the full list of guidelines at
// http://go.microsoft.com/fwlink/?LinkID=85237
// and also the guidance for operator== at
// http://go.microsoft.com/fwlink/?LinkId=85238
//
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var data = (accessoire)obj;
return this.Ref.Equals(data.Ref);
}
// override object.GetHashCode
public override int GetHashCode()
{
return this.Ref.GetHashCode()
}
You were doing reference compare and the references don't match in your first example, but do in your second. You probably want to do equality comparison. Are the values of both objects the same.
Below is your class implemented with the various methods used for equality comparing. You would just need to modify them to suit your purposes.
// IEquatable<T> provides typed equality comparing
class accessoire : IEquatable<accessoire>
{
public int Value1 { get; set; }
public string Value2 { get; set; }
// you can override Equals.
public override bool Equals(object obj)
{
return this.Equals(obj as accessoire);
}
// this comes from IEquatable<T>
public bool Equals(accessoire other)
{
if (ReferenceEquals(null, other))
{
return false;
}
// return the comparison that makes them equal.
return
this.Value1.Equals(this.Value1) &&
this.Value2.Equals(this.Value2);
}
public override int GetHashCode()
{
unchecked
{
int hash = 37;
hash *= 23 + this.Value1.GetHashCode();
hash *= 23 + this.Value2.GetHashCode();
return hash;
}
}
// allows you to check equality with the == operator
public static bool operator ==(accessoire left, accessoire right)
{
if (ReferenceEquals(left, right))
{
return true;
}
if ((oject)left == null || (object)right == null)
{
return false;
}
return left.Equals(right);
}
public static bool operator !=(accessoire left, accessoire right)
{
return !left.Equals(right);
}
}
I've got an object which has 3 integer values, combined the 3 integer are always unique. I want a quick way to find the specific object out of thousands.
my idea was to combine the 3 integers in a string so 1, 2533 and 9 would become a unique string: 1-2533-9. But is this the most efficient way? The numbers cannot be bigger than 2^16, so I could also use bit shifting and create a long which would be faster than creating a string from them I think. Are there other options? what should I do?
The main thing I want to achieve is finding the object quickly even with a collection of thousands of objects.
public class SomeClass
{
private readonly IDictionary<CompositeIntegralTriplet, object> _dictionary = new Dictionary<CompositeIntegralTriplet, object>();
}
public sealed class CompositeIntegralTriplet : IEquatable<CompositeIntegralTriplet>
{
public CompositeIntegralTriplet(int first, int second, int third)
{
First = first;
Second = second;
Third = third;
}
public int First { get; }
public int Second { get; }
public int Third { get; }
public override bool Equals(object other)
{
var otherAsTriplet = other as CompositeIntegralTriplet;
return Equals(otherAsTriplet);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = First;
hashCode = (hashCode*397) ^ Second;
hashCode = (hashCode*397) ^ Third;
return hashCode;
}
}
public bool Equals(CompositeIntegralTriplet other) => other != null && First == other.First && Second == other.Second && Third == other.Third;
}
var s1=new Student{ id=1,name="Sachin" }
var s2=new Student{ id=1,name="Sachin" }
The question is if s1 is equal to s2 then answer will be false, however what is the method to make s1 equal to s2?
You have to override Equals and GetHashCode, otherwise only references are compared:
public class Student
{
public int Id { get; set; }
public string Name { get;set; }
public override bool Equals(object obj)
{
Student s2 = obj as Student;
if (s2 == null) return false;
return this.Equals(s2);
}
public bool Equals(Student s)
{
if (s == null) return false;
return Id == s.Id && Name == s.Name;
}
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + Id;
hash = hash * 23 + Name.GetHashCode();
return hash;
}
}
}
In this example two students are equal only if both, the id and the name are equal. Change it accordingly.
It is not really necessary to overload Equals(Student) and to override also GetHashCode. But it is strongly recommended. Read: Guidelines for Overloading Equals()
Assuming your ID field is unique between all users, why not use that as your equality check?
if (s1.id == s2.id) {
...
}
It's usually best to start with the simplest solution before delving into the more complicated way, you might find it's all you need.
I need your help. I am trying to get distinct values from List of objects.
My class looks like this:
class Chromosome
{
public bool[][] body { get; set; }
public double fitness { get; set; }
}
Now I have List<Chromosome> population. And now what I need is a way, how I can get new list: List<Chromosome> newGeneration. This new list will contain only unique chromosomes from original list - population.Chromosome is unique, when his whole body (which in this case is 2D bool array) is unique in comparison to the other chromosomes.
I know, that there is something like MoreLINQ, but I am not sure, whether I should use 3rd party code and I know that I should overwrite some methods, but I am kind of lost. So I would really appreciate some nice step by step description, that even idiot could accomplish :)
THX
First, implement the equality operator (this goes into class Chromosome):
public class Chromosome : IEquatable<Chromosome>
{
public bool[][] body { get; set; }
public double fitness { get; set; }
bool IEquatable<Chromosome>.Equals(Chromosome other)
{
// Compare fitness
if(fitness != other.fitness) return false;
// Make sure we don't get IndexOutOfBounds on one of them
if(body.Length != other.body.Length) return false;
for(var x = 0; x < body.Length; x++)
{
// IndexOutOfBounds on inner arrays
if(body[x].Length != other.body[x].Length) return false;
for(var y = 0; y < body[x].Length; y++)
// Compare bodies
if(body[x][y] != other.body[x][y]) return false;
}
// No difference found
return true;
}
// ReSharper's suggestion for equality members
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != this.GetType())
{
return false;
}
return this.Equals((Chromosome)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((this.body != null ? this.body.GetHashCode() : 0) * 397) ^ this.fitness.GetHashCode();
}
}
}
Then, use Distinct:
var newGeneration = population.Distinct().ToList();
public class ChromosomeBodyComparer : IEqualityComparer<Chromosome>
{
private bool EqualValues(bool[][] left, bool[][] right)
{
if (left.Length != right.Length)
{
return false;
}
return left.Zip(right, (x, y) => x.SequenceEquals(y)).All();
}
public bool Equals(Chromosome left, Chromosome right)
{
return EqualValues(left.body, right.body)
}
//implementing GetHashCode is hard.
// here is a rubbish implementation.
public int GetHashCode(Chromosome c)
{
int numberOfBools = c.body.SelectMany(x => x).Count();
int numberOfTrues = c.body.SelectMany(x => x).Where(b => b).Count();
return (17 * numberOfBools) + (23 * numberOfTrues);
}
}
Called by:
List<Chromosome> nextGeneration = population
.Distinct(new ChromosomeBodyComparer())
.ToList();
I need to arrange sort of dictionary where the key would be a pair of enum and int
and value is object. So I want to map a pair to some object.
One option would be
public enum SomeEnum
{
value1, value2
}
class Key
{
public SomeEnum;
public int counter;
// Do I have to implement Compare here?
}
Dictionary<SomeEnum, object> _myDictionary;
Another option would convert enum and int to some unique key.
string key = String.Format("{0}/{1}", enumValue, intValue)
That approach requires string parsing, a lot of extra work.
How to make it easily?
I would go with something similar to
public enum SomeEnum
{
value1, value2
}
public struct Key
{
public SomeEnum;
public int counter;
}
Dictionary<Key, object>
I think that would make it?
If you are going to put this in a dictionary, then you will need to make sure you implement a meaningful .Equals and .GetHashCode or the dictionary will not behave correctly.
I'd start off with something like the following for the basic compound key, and then implement a custom IComparer to get the sort order you need.
public class MyKey
{
private readonly SomeEnum enumeration;
private readonly int number;
public MyKey(SomeEnum enumeration, int number)
{
this.enumeration = enumeration;
this.number = number;
}
public int Number
{
get { return number; }
}
public SomeEnum Enumeration
{
get { return enumeration; }
}
public override int GetHashCode()
{
int hash = 23 * 37 + this.enumeration.GetHashCode();
hash = hash * 37 + this.number.GetHashCode();
return hash;
}
public override bool Equals(object obj)
{
var supplied = obj as MyKey;
if (supplied == null)
{
return false;
}
if (supplied.enumeration != this.enumeration)
{
return false;
}
if (supplied.number != this.number)
{
return false;
}
return true;
}
}
If you are using C# 4.0, you could use the Tuple class.
var key = Tuple.Create(SomeEnum.Value1, 3);