Best HashSet Search Method

I have a HashSet Objs with Obj defined as such:

public class Obj { private int _id; private string _desc; private int _sum; public int Id { get { return _id; } set { _id = value; } } public string Description { get { return _desc; } set { _desc = value; } } public int Sum { get { return _sum; } set { _sum = value; } } public Obj(int id, string desc, int sum) { _id = id; _sum = sum; _desc = desc; } public override bool Equals(Obj other) { return this._sum == other._sum && this._desc == other._desc; } public override int GetHashCode() { int hash = 13; hash = (hash * 7) + _sum.GetHashCode(); hash = (hash * 7) + _desc.GetHashCode(); return hash; } } 

This works fine, but I am having trouble retrieving from a HashSet when HashSet.Add(obj) returns false. What would be the best way to get the _id Obj that is already contained in the HashSet in that case?

+7
c #
source share
4 answers

As I see it: sum + description (used for hashcode, equals) = key and _id (what you want to get) = value.

The script clearly points to a dictionary, not a hashset .... sets are not intended for arbitrary search / search.

+5
source share
 myHashSet.First(x => x.Equals(myItemToRetrieve)).Id; 

Another way to do this is to use a dictionary (keys are equal values):

(assuming you converted it):

 Obj temp; if (theDictionary.TryGetValue(myItemToRetrieve, out temp)) { int ID = temp.Id; } else { theDictionary[myItemToRetrieve] = myItemToRetrieve; } 
+3
source share

You can define your own collection type, which is built on Dictionary<TKey, TValue> and provides the GetOrAdd method (similar to GetOrAdd ConcurrentDictionary<TKey, TValue> ):

 public partial class HashDictionary<T> : Dictionary<T, T> { public T GetOrAdd(T newItem) { T oldItem; if (this.TryGetValue(newItem, out oldItem)) return oldItem; this.Add(newItem, newItem); return newItem; } } 

To use this, you must call:

 Obj presentO = myHashDictionary.GetOrAdd(newO); if (presentO == newO) { // The item was not already present, and has been added. } else { // A collision occurred, and presentO points to the existent item. int alreadyContainedID = presentO.ID; } 

To maintain compatibility with your current code, you can extend this class to implement ICollection<T> (or, preferably, ISet<T> ):

 public partial class HashDictionary<T> : ICollection<T> { public void Add(T item) { this.GetOrAdd(item); } public bool Contains(T item) { return this.ContainsKey(item); } public void CopyTo(T[] array, int arrayIndex) { this.Keys.CopyTo(array, arrayIndex); } public bool IsReadOnly { get { return false; } } public new IEnumerator<T> GetEnumerator() { return this.Keys.GetEnumerator(); } } 
+1
source share

I had problems with this situation in the past. Of course, I used Dictionary <TKey, TValue>, which makes it easier to get a key based object. When you redefine a hash code, one problem is that hashtables and such entries are stored according to INITIAL values. Therefore, if you play a little with the object, you will no longer be able to restore the object, because the hash code has been changed. So the trick I used was to have an integer hash code with a separate method like

 private hashcode; public void UpdateHashCode(){ hashcode = // your original logic here. } 

This way you can control when the hash code will be updated so that you can find the old object. remove it from the dictionary, then update your object and then save the modified object.

But purists will not like this, as this means that strict equality testing and hash testing will not work correctly with modified objects that have not updated the hash. Therefore, instead, you can simply track the old hash code as a separate property, which is updated only after adding it to the dictionary.

 private int oldHashcode; public int OldHashcode{ get{ return oldHashCode; } set { oldHashCode = value; } } 

And when you add to the dictionary:

 item.OldHashCode = item.GetHashCode(); 

And to extract

 item = myDictionary[item.OldHashCode]; 

or something else.

0
source share

All Articles