什么时候应该使用HashSet <T>types?
我正在探索HashSet<T>
types,但我不明白它在集合中的位置。
可以用它来代替List<T>
吗? 我想HashSet<T>
的性能会更好,但是我看不到其元素的单独访问。
仅仅是枚举吗?
关于HashSet<T>
的重要之处就在于它的名字:它是一个集合 。 唯一可以做的事情就是确定其成员是什么,并检查一个项目是否是成员。
询问是否可以检索单个元素(例如set[45]
)会误解该集合的概念。 没有这样的事情,作为一个集合的第45个元素。 一组中的项目没有sorting。 集合{1,2,3}和{2,3,1}在各方面是相同的,因为它们具有相同的成员资格,并且成员资格是重要的。
迭代HashSet<T>
有点危险,因为这样做会对集合中的项目施加一个顺序。 这个命令并不是这个集合的一个属性。 你不应该依赖它。 如果集合中的物品的订购对您来说很重要,那么这个集合不是一个集合。
集合是非常有限的,并与独特的成员。 另一方面,他们真的很快。
下面是我使用HashSet<string>
的一个真实例子:
我的UnrealScript文件语法高亮部分是一个突出Doxygen风格的注释的新function。 我需要能够判断@
或\
命令是否有效,以确定是以灰色(有效)还是红色(无效)显示。 我有一个所有有效的命令的HashSet<string>
,所以每当我在词法分析器中打一个@xxx
标记,我使用validCommands.Contains(tokenText)
作为我的O(1)有效性检查。 我真的不在乎除了有效命令集中命令的存在。 让我们看看我面临的替代scheme:
-
Dictionary<string, ?>
:我使用什么types的值? 这个值是没有意义的,因为我只是要使用ContainsKey
。 注意:在.NET 3.0之前,这是O(1)查找的唯一select – 为3.0添加了HashSet<T>
,并对4.0进行了扩展以实现ISet<T>
。 -
List<string>
:如果我保持列表sorting,我可以使用BinarySearch
,它是O(log n)(没有看到上面提到的这个事实)。 然而,由于我的有效命令列表是一个永远不会改变的固定列表,这将永远不会比简单… -
string[]
:同样,Array.BinarySearch
给出了O(log n)的性能。 如果名单很短,这可能是performance最佳的select。 它总是比HashSet
,Dictionary
或List
有更less的空间开销。 即使使用BinarySearch
,大集合也不会更快,但对于小集合来说,这是值得尝试的。 虽然我有几百件东西,所以我通过了这个。
HashSet<T>
实现了ICollection<T>
接口:
public interface ICollection<T> : IEnumerable<T>, IEnumerable { // Methods void Add(T item); void Clear(); bool Contains(T item); void CopyTo(T[] array, int arrayIndex); bool Remove(T item); // Properties int Count { get; } bool IsReadOnly { get; } }
List<T>
实现了IList<T>
,它扩展了ICollection<T>
public interface IList<T> : ICollection<T> { // Methods int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index); // Properties T this[int index] { get; set; } }
HashSet已经设置了语义,通过哈希表在内部实现:
集合是不包含重复元素的集合,其元素没有特定的顺序。
如果HashSet失去了索引/位置/列表行为,它会得到什么?
从HashSet添加和检索项目总是由对象本身而不是通过索引器,并且接近O(1)操作(List是O(1)add,O(1)通过索引检索O(n)find /去掉)。
一个HashSet的行为可以通过添加/删除键作为值来比较使用Dictionary<TKey,TValue>
,并忽略字典值本身。 您会希望字典中的键不会有重复的值,这就是“设置”部分的重点。
性能将是一个糟糕的理由selectHashSet而不是List。 相反,什么更好地捕捉你的意图? 如果顺序很重要,那么Set(或HashSet)就出来了。 如果重复,也是如此。 但是当我们不关心订单的时候,我们有很多情况,我们宁愿不要重复 – 那就是当你想要一个集合时。
HashSet是由散列实现的一个集合 。 一个集合是不包含重复元素的值的集合。 一组中的值通常也是无序的。 所以不,一个集合不能用来replace一个列表(除非你首先使用一个集合)。
如果你想知道什么样的设置可能是好的:显然,你想摆脱重复的地方。 作为一个稍微做作的例子,假设你有一个软件项目的10.000版本的列表,你想知道有多less人为这个项目做出了贡献。 您可以使用Set<string>
并遍历修订列表,并将每个修订版本的作者添加到集合中。 一旦你完成了迭代,集合的大小就是你正在寻找的答案。
哈希集合最常见的用途是查看它们是否包含某个元素,它接近于O(1)操作(假设一个足够强的哈希函数),而不是包含检查的列表是O( n)(以及它是O(log n)的sorting集)。 所以,如果你做了很多检查,某个项目是否包含在某个列表中,则可能会提高性能。 如果你只是遍历它们,那么不会有太大的区别(遍历整个集合是O(n),与列表相同,并且在添加项目时,哈希集合有更多的开销)。
不,你不能索引一套,因为套不是有序的,所以无论如何也没有意义。 如果你添加一些项目,设置将不会记得哪一个是第一个,哪个第二等。
HashSet将用于删除IEnumerble集合中的重复元素。 例如,
List<string> duplicatedEnumrableStrings = new List<string> {"abc", "ghjr", "abc", "abc", "yre", "obm", "ghir", "qwrt", "abc", "vyeu"}; HashSet<string> uniqueStrings = new HashSet(duplicatedEnumrableStrings);
在这些代码运行后,uniqueStrings会保存{“abc”,“ghjr”,“yre”,“obm”,“qwrt”,“vyeu”};
List<T>
用于存储有序的信息集合。 如果您知道列表元素的相对顺序,则可以在一段时间内访问它们。 但是,要确定元素在列表中的位置或者检查它是否存在于列表中,查找时间是线性的。 另一方面, HashedSet<T>
不保证存储数据的顺序,因此为其元素提供了不断的访问时间。
顾名思义, HashedSet<T>
是一个实现集合语义的数据结构。 数据结构被优化以实现集合操作(即联合,差异,相交),这不能像传统的List实现那样有效地完成。
因此,select使用哪种数据types取决于您正在尝试使用哪种数据types。 如果你不关心你的元素是如何在一个集合中进行sorting的,而只是想要检查是否存在,请使用HashSet<T>
。 否则,请考虑使用List<T>
或其他合适的数据结构。
HashSet<T>
是.NET框架中的一种数据结构,能够将math集合表示为对象。 在这种情况下,它使用哈希码(每个项目的GetHashCode
结果)来比较设置元素的相等性。
一个集合与一个列表的不同之处在于,它只允许在其中包含相同元素的一次出现。 如果尝试添加第二个相同的元素, HashSet<T>
将仅返回false
。 事实上,查找元素非常快( O(1)
时间),因为内部数据结构只是一个哈希表。
如果您想知道要使用哪一个,请注意,使用List<T>
其中HashSet<T>
适用)不是最大的错误,尽pipe它可能会允许在您的集合中存在不需要的重复项目的问题。 更重要的是,查找(项目检索)效率要高得多 – 理想的情况是O(1)
(用于完美的分包)而不是O(n)
时间 – 这在很多情况下非常重要。
简而言之 – 无论何时你想使用一个字典(或一个字典,其中S是T的一个属性),那么你应该考虑一个HashSet(或HashSet +在T上实现IEquatable,这相当于S)