I am using RTBTextPointer as custom key in dictionary...
Init.SpintaxEditorPropertyMain.SpintaxListDict = new Dictionary<RTBTextPointer, SpintaxEditorProperties.SpintaxMappedValue>(new RTBTextPointerComparer());
I worte this RTBTextPointer, and RTBTextPointerComparer classes in class library and using this in different wpf projects,
if (Init.SpintaxEditorPropertyMain.SpintaxListDict.ContainsKey(_index) == false)
{
Init.SpintaxEditorPropertyMain.SpintaxListDict.Add(_index,_SpintaxMappedVal);
}
everytime containsKey returns false, even it contains, so duplication entry occurs in dictionary.. is anything wrong in my "GetHashCode()"
public class RTBTextPointer
{
static int _row;
static int _column;
public int Row
{
get
{
return _row;
}
set
{
_row = value;
}
}
public int Column
{
get
{
return _column;
}
set
{
_column = value;
}
}
}
public class RTBTextPointerComparer : IEqualityComparer<RTBTextPointer>
{
public bool Equals(RTBTextPointer x, RTBTextPointer y)
{
bool result = int.Equals(x.Column, y.Column) && (int.Equals(x.Row, y.Row));
return result;
}
public int GetHashCode(RTBTextPointer obj)
{
var result = 0;
int hCode = obj.Column ^ obj.Row;
result = hCode.GetHashCode();
return result;
}
}
Please help me
Thanks in advance
I don't think you need to create a separate comparer. Just overriding Equals and GetHashCode should suffice.
Also, if you have very simple properties like that, you could switch to auto properties
public class RTBTextPointer
{
public int Row
{
get;
set;
}
public int Column
{
get;
set;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
var other = obj as RTBTextPointer;
if (other == null)
{
return false;
}
return other.Row == Row && other.Column == Column;
}
public override int GetHashCode()
{
unchecked
{
// 397 or some other prime number
return (Row * 397) ^ Column;
}
}
}
See unchecked for more information about that.
If you have more than two properties, and if those properties could be null, the GetHashCode might look like this:
unchecked
{
var result = 0;
result = (result * 397) ^ (Prop1 != null ? Prop1.GetHashCode() : 0);
result = (result * 397) ^ (Prop2 != null ? Prop2.GetHashCode() : 0);
result = (result * 397) ^ (Prop3 != null ? Prop3.GetHashCode() : 0);
result = (result * 397) ^ (Prop4 != null ? Prop4.GetHashCode() : 0);
// ...
return result;
}
Your problem probably stems from the following declarations in RTBTextPointer:
static int _row;
static int _column;
These don't do what I think you're intending. They should be
private int _row;
private int _column;
As it is right now, these variables reference static members of RTBTextPointer. This means that any access of them will access or mutate the static members of it. static members are accessible to every instance of a type. If you make them private, they will apply per instance, which I believe is your intent.
Once that is corrected, I would reconsider the design of your class, at least if you intent to use it as a key in a Dictionary. RTBTextPointer should be immutable, or atleast the fields and properties that GetHashCode() depends on. Here's why:
When you add a object as a key to a dictionary, it's associated value is placed in a hash bucket , which is simply some data structure associated with a hash code. Assume we have some arbitrary key RTBTextPointer with Row = 2 and Column = 2 and a value of "Foo". It's GetHashCode would be 0 (2 XOR 2).
Hash Key Value
0 RTBTextPointer(2,2) Foo
Right now, a call to Dictionary.ContainsKey() would return true looking for RTBTextPointer(2,2). Now consider if this RTBTextPointer changed to have a Row = 4. It's hash code would now be 6 (4 XOR 2). The call to Dictionary.ContainsKey() would now be false, and the value Foo would be inaccessible because the key has a hash code that depends upon mutable state.
As a final note, I would consider overriding the Equals() and GetHashCode() methods of object.
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;
}
I have the following two lists:
List<MyObject> oldList = new List<MyObject>();
oldList.Add(new MyObject { Id = 1, Name = "hello" });
oldList.Add(New MyObject { Id = 2, Name = "world" });
List<MyObject> newList = new List<MyObject>();
newList.Add(new MyObject { Id = 1, Name = "Hello" });
newList.Add(new MyObject { Id = 3, Name = "World" });
newList.Add(new MyObject { Id = 4, Name = "hello" });
I would like to write something to compare the two lists and return boolean true if the lists are different.
For example, the lists above are different in the following ways:
Id's don't exactly match
Counts don't match
In cases where Id's do match, the Name's don't exactly match (case-sensitive)
I have tried the following:
if (oldList != newList)
And:
if (!oldList.SequenceEqual(newList))
However, both produce inaccurate results. I understand I can create a class of type IEqualityComparer which implements a HashSet comparison; but I also read that it may not work for my case... Can someone shed any light on how to compare two objects to detect the types of changes I have specified?
As you've said, you only need to implement the correct IEquatable<MyObject> interface in your MyObject, or implement an IEqualityComparer<MyObject>
/// <summary>
/// Fully equatable MyObject
/// </summary>
public class MyObject : IEquatable<MyObject>
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyObject other = obj as MyObject;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyObject other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyObject other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.Id == other.Id && this.Name == other.Name;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.Id.GetHashCode();
hash = hash * 23 + (this.Name != null ? this.Name.GetHashCode() : 0);
return hash;
}
}
}
and then you can use
if (!oldList.SequenceEqual(newList))
Note that this will compare element order! If you change element order, then the comparison will return false
Or you can use an "external" IEqualityComparer<MyObject>
public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
public static readonly MyObjectEqualityComparer Default = new MyObjectEqualityComparer();
protected MyObjectEqualityComparer()
{
}
public bool Equals(MyObject x, MyObject y)
{
if (object.ReferenceEquals(x, null))
{
return object.ReferenceEquals(y, null);
}
if (object.ReferenceEquals(y, null))
{
return false;
}
// Here we know that x != null && y != null;
if (object.ReferenceEquals(x, y))
{
return true;
}
return x.Id == y.Id && x.Name == y.Name;
}
public int GetHashCode(MyObject obj)
{
if (obj == null)
{
return 0;
}
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + obj.Id.GetHashCode();
hash = hash * 23 + (obj.Name != null ? obj.Name.GetHashCode() : 0);
return hash;
}
}
}
use it like
if (!oldList.SequenceEqual(newList, MyObjectEqualityComparer.Default))
Note that there are various schools of thought on how exactly to write equality comparers, and there is a little caveat: if you override the operator== you must be very very wary of not using it inside your comparator :-)
A classical example of wrong code, when the operator== is overloaded
public bool Equals(MyObject other)
{
// BOOOM!!! StackOverflowException!
// Equals will call operator== that will probably call
// Equals back! and so on and so on.
if (other == null)
{
return false;
}
return this.InnerEquals(other);
}
So it is better to do object.ReferenceEquals(something, someotherthing) that does reference comparison.
Then there is the problem of null handling with properties:
The hash of Name (a string) is written like this:
hash = hash * 23 + obj.Name != null ? obj.Name.GetHashCode() : 0
so that if obj.Name is null the code doesn't expode in a NullReferenceException. Automatically generated code for anonymous objects use another way:
hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(obj.Name);
The EqualityComparer<string>.Default is safe to use, even with null values.
For the Equals comparison of properties, the automatically generated code for anonymous objects uses another funny trick:
&& EqualityComparer<string>.Default.Equals(this.Name, obj.Name);
so it uses EqualityComparer<string>.Default.Equals, that then correctly uses the various methods/interfaces to compare objects.
I have a class that was previously being used in a HashSet. This has now been changed so that the class is now used in a SortedSet, but the equality test no longer works as it did. I believe this it uses the CompareTo function for both sorting and comparing, and this is by design.
Anyone have any ideas, other than performing my own duplicate checks?
public sealed class DatedID : IEquatable<DatedID>, IComparable
{
readonly DateTime _added;
readonly int _ID;
public DateTime Added
{
get { return _added; }
}
public int ID
{
get { return _ID; }
}
public DatedID(int id)
: this(id, DateTime.Now) {}
public DatedID(int id, DateTime added)
{
id.ThrowDefault("id");
added.ThrowDefault("added");
_ID = id;
_added = added;
}
// Compare
int IComparable.CompareTo(object obj)
{
var other = (DatedID)obj;
// Newest => oldest
return this.Added > other.Added ? -1 : this.Added < other.Added ? 1 : 0;
}
// Equals
public bool Equals(DatedID other)
{
if (other == null) return false;
return this.ID == other.ID;
}
public override bool Equals(object obj)
{
if (obj == null) return false;
var di = obj as DatedID;
return di == null ? false : Equals(di);
}
public override int GetHashCode()
{
return ID.GetHashCode();
}
}
If you mean you need to be able to handle multiple values with different IDs but the same DateTime, you could include that in your CompareTo implementation:
// TODO: Implement IComparable<DatedID> as well :)
int IComparable.CompareTo(object obj)
{
var other = (DatedID)obj;
int dateComparison = other.Added.CompareTo(this.Added);
return dateComparison != 0
? dateComparison
: _ID.CompareTo(other._ID);
}
If you mean you don't want to be able to add multiple values with the same ID but different dates, then you can't achieve that with SortedSet. In SortedSet, the only measure of equality is if the comparison returns 0.
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();