搜索HashSet的最佳方式

时间:2013-07-22 20:42:10

标签: c#

我有一个Objs的HashSet,Obj定义如下:

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.Add(obj)返回false时,我无法从HashSet中检索。在这种情况下,检索_id中已包含的Obj HashSet的最佳方法是什么?

4 个答案:

答案 0 :(得分:5)

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

该场景清楚地指向字典而不是散列集....集合不适用于任意查找/检索。

答案 1 :(得分:3)

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

另一种方法是使用Dictionary(键值相等):

(假设你已将其转换):

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

答案 2 :(得分:1)

您可以定义基于Dictionary<TKey, TValue>构建的自己的集合类型,并提供GetOrAdd方法(类似于ConcurrentDictionary<TKey, TValue>的{​​{3}}):

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

答案 3 :(得分:0)

过去我遇到过这种情况的麻烦。当然,我使用的是Dictionary&lt; TKey,TValue&gt;,这样可以更容易地根据键获取对象。当您覆盖哈希码时,一个问题是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];

或其他什么。