2013-07-22 75 views
7

的方式,我有OBJ文件所有與obj定義爲這樣的一個HashSet:最佳搜索HashSet的

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; 
    } 
} 

這工作得很好,但我無法從HashSet的檢索時HashSet.Add(obj)返回false。在這種情況下,檢索HashSet中已包含的Obj_id的最佳方法是什麼?

+0

Double'_'s?錯誤與否? –

+2

私有變量的任何原因。你可以做'公衆詮釋ID {get; set;}' – gunr2171

+0

@newStackExchangeInstance對不起,這是一個錯字。 – ashishduh

回答

5

我看到它的方式:sum + description(用於hashcode,equals)= key和_id(你想要檢索的)= value。

該場景明確指向字典而不是哈希集....集不適用於任意查找/檢索。

+0

但是OP並不是真的想要一個字典,他們想要檢索一個*規範元素*。當然,這可以表示爲映射。但設置查找會更直接。 (但我同意在這裏使用'Dictionary'是最好的實際解決方案)。 –

+0

我結束了與詞典。考慮到我的數據設置,這並沒有太大的邏輯意義,但實際上,康拉德魯道夫說,這很有意義。 – ashishduh

3
myHashSet.First(x => x.Equals(myItemToRetrieve)).Id; 

另一種方式做,這是使用字典(鍵相等的值):

(假設你已經將它轉換):

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

這個解決方案的問題在於迭代的複雜性(與'First'一起使用) –

+0

請注意,使用'HashSet'的重點在於避免線性搜索。 – Servy

+1

@Servy可能有適當的散列集。不與在別名「HashSet」下帶有.NET的'RetardedHashSet'。 –

0

我有麻煩與此情況過去。當然,我使用的字典< TKey,TValue >,這使得它更容易獲得基於關鍵的對象。當你重寫散列碼時,一個問題就是Hashtables等根據INITIAL值存儲記錄。所以如果你用對象來擺弄一下,你將不再能夠恢復對象,因爲哈希碼已經改變了。所以,我用的伎倆是有一個單獨的方法的哈希碼像

private hashcode; 

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

} 

這樣一來,當哈希碼被更新,你可以控制,所以你仍然可以找到你的老物件。從字典中刪除它,然後更新您的對象,然後存儲修改後的對象。

但純粹主義者不會這樣,因爲這意味着嚴格的平等測試和哈希測試將無法正確工作在修改對象沒有更新哈希。因此,您可以將舊哈希代碼作爲單獨的屬性進行跟蹤,只有在將它添加到字典時纔會更新。

private int oldHashcode; 

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

而當你添加到字典:

item.OldHashCode = item.GetHashCode(); 

,並檢索

item = myDictionary[item.OldHashCode]; 

或什麼的。

+0

這不是真的OP的問題,雖然它是真的。然而,在OP的情況下,'Id'根本不構成對象身份的一部分。其餘部分保持不變,對象的散列值也是如此。 –

+0

啊,我認爲他原則上已經知道如何從HashSet中取回對象,但遇到了問題。 – Ted

1

您可以定義建立在Dictionary<TKey, TValue>,並提供了GetOrAdd方法(類似於ConcurrentDictionary<TKey, TValue>GetOrAdd)自己的集合類型:

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; 
    } 
} 

要使用此,你會打電話:

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; 
} 

爲了保持與您當前的代碼的兼容性,您可以擴展此類以實現ICollection<T>(或者,最好是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(); 
    } 
}