简体   繁体   English

为什么我会在字典上使用HashSet?

[英]Why would I use a HashSet over a Dictionary?

I'm trying to implement a list of cached paths on a A* algorithm. 我正在尝试在A *算法上实现缓存路径列表。 Currently, the cached paths are stored in a list like this: 目前,缓存的路径存储在如下列表中:

readonly List<CachedPath> _cachedPaths = new List<CachedPath>();

The operations performed over this list are: 在此列表上执行的操作是:

FirstOrDefault to get an element that satisfies certain conditions FirstOrDefault获取满足某些条件的元素

var cached = _cachedPaths.FirstOrDefault(p => p.From == from && p.To == target && p.Actor == self);

Remove and element 删除和元素

_cachedPaths.Remove(cached);

Additions 附加

_cachedPaths.Add(new CachedPath {
                    From = from,
                    To = target,
                    Actor = self,
                    Result = pb,
                    Tick = _world.WorldTick
                });

NOTE: The class CachedPath has GetHashCode and Equals overriden by just the From, To and Actor, so two instances that have these same attributes have the same hash and equality. 注意:类CachedPath只有From,To和Actor覆盖GetHashCode和Equals,因此具有这些相同属性的两个实例具有相同的散列和相等性。

Given that quick lookups (Contains), insertions and deletions in a 'HashSet' are O(1) (if I'm not mistaken), I considered using a 'HashSet' to do these operations. 鉴于快速查找(包含),'HashSet'中的插入和删除是O(1)(如果我没有弄错),我考虑使用'HashSet'来执行这些操作。 The only problem is the FirstOrDefault, that I had to enumerate the whole collection to get it. 唯一的问题是FirstOrDefault,我必须枚举整个集合才能得到它。

Given this problem, I considered also using a Dictionary indexed by the hash of From, To and Actor: 鉴于此问题,我还考虑使用由From,To和Actor的哈希索引的Dictionary:

Dictionary<int, CachedPath> cachedPath

Once again, if I'm not mistaken, Dictionary also offers O(1) in insertions, deletions, and also retrieval by Key. 再一次,如果我没有弄错的话,Dictionary还提供O(1)插入,删除和Key检索。 This leads me to think that a Dictionary is a HashSet + O(1) element retrieval capabilities. 这使我认为Dictionary是HashSet + O(1)元素检索功能。

Am I missing something? 我错过了什么吗? Is really Dictionary better than HashSet in the sense that it supports more operations? 在它支持更多操作的意义上,字典真的比HashSet好吗?

Thanks in advance. 提前致谢。

Dictionary is not better than HashSet , it's just different. Dictionary也不好过 HashSet ,它只是不同。

  • You use a HashSet when you want to store an unordered collection of items, and 当您想要存储无序的项集合时,可以使用HashSet
  • You use a Dictionary when you want to associate a set of items called "keys" with another collection of items called "values" 如果要将名为“keys”的一组项与另一个名为“values”的项目集合相关联,请使用Dictionary

One could think of a HashSet as a Dictionary with no associated values (in fact, HashSet is sometimes implemented using a Dictionary behind the scene) but it is not necessary to think about it in this way: thinking of the two as of entirely different things works fine, too. 可以将HashSet视为没有关联值的Dictionary (实际上, HashSet有时使用场景后面的Dictionary实现)但是没有必要以这种方式思考它:将两者视为完全不同的东西工作得很好。

In your case you could potentially improve performance by making a dictionary by actor, like this: 在您的情况下,您可以通过按actor创建字典来提高性能,如下所示:

Dictionary<ActorType,List<CachedPath>> _cachedPathsByActor

This way your linear search would quickly choose a sub-list based on an actor, and then search linearly by target: 这样,线性搜索会快速选择基于actor的子列表,然后按目标线性搜索:

var cached = _cachedPathsByActor[self].FirstOrDefault(p => p.From == from && p.To == target);

or by making an equality comparer that considers all three items, and using a Dictionary with CachedPath as both keys and values, and that custom IEqualityComparer<T> as the key comparer: 或者通过创建一个考虑所有三个项目的相等比较器,并使用带有CachedPathDictionary作为键和值,并将自定义IEqualityComparer<T>作为键比较器:

class CachedPathEqualityComparer : IEqualityComparer<CachedPath> {
    public bool Equals(CachedPath a, CachedPath b) {
        return a.Actor == b.Actor
            && a.From == b.From
            && a.To == b.To;
    }
    public int GetHashCode(CachedPath p) {
        return 31*31*p.Actor.GetHashCode()+31*p.From.GetHashCode()+p.To.GetHashCode();
    }
}
...
var _cachedPaths = new Dictionary<CachedPath,CachedPath>(new CachedPathEqualityComparer());
...
CachedPath cached;
if (_cachedPaths.TryGetValue(self, out cached)) {
    ...
}

However, this approach assumes that there would be at most one item in the dictionary with identical From , To , and Actor . 但是,这种方法假定字典中最多只有一个项目具有相同的FromToActor

A hashset will not throw an exception when performing an add. 执行添加时,哈希集不会引发异常。 Instead it returns a bool reflecting success of the add. 相反,它返回一个反映add成功的bool。

Also a hashset does not require a keyValue pair. 此外,散列集不需要keyValue对。 I use hashsets to guarantee a collection of unique values. 我使用hashsets来保证一组唯一值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM