我正在探索HashSet<T>
类型,但我不明白它在集合中的位置。
可以用它来代替List<T>
吗?我认为HashSet<T>
的表现会更好,但我看不到个人对其元素的访问。
仅用于枚举吗?
答案 0 :(得分:220)
HashSet<T>
的重要之处就在于名称:它是集。单个集合中唯一可以做的就是确定其成员是什么,并检查项目是否是成员。
询问是否可以检索单个元素(例如set[45]
)是误解了集合的概念。没有集合中的第45个元素。集合中的项目没有排序。集合{1,2,3}和{2,3,1}在各方面都是相同的,因为它们具有相同的成员资格,并且成员资格是最重要的。
迭代HashSet<T>
有点危险,因为这样做会对集合中的项目施加顺序。该订单实际上不是该集合的属性。你不应该依赖它。如果对集合中的项目进行排序对您来说很重要,那么该集合就不是一个集合。
集合非常有限且具有唯一成员。另一方面,他们真的很快。
答案 1 :(得分:103)
以下是我使用HashSet<string>
:
UnrealScript文件的部分语法高亮显示是highlights Doxygen-style comments的新功能。我需要能够判断@
或\
命令是否有效,以确定是以灰色(有效)还是红色(无效)显示。我有HashSet<string>
个有效命令,所以每当我点击词法分析器中的@xxx
标记时,我都会使用validCommands.Contains(tokenText)
作为我的O(1)有效性检查。除了有效命令的 set 中的命令的存在之外,我真的不关心任何事情。让我们看看我面临的替代方案:
Dictionary<string, ?>
:我使用什么类型的值?由于我将使用ContainsKey
,因此该值毫无意义。注意:在.NET 3.0之前,这是O(1)查找的唯一选择 - 为3.0添加HashSet<T>
并扩展为4.0实现ISet<T>
。List<string>
:如果我对列表进行排序,我可以使用BinarySearch
,即O(log n)(没有看到上面提到的这个事实)。但是,由于我的有效命令列表是一个永不改变的固定列表,因此这将永远不会比简单... string[]
:Array.BinarySearch
再次给出O(log n)性能。如果列表很短,这可能是表现最佳的选项。它的空间开销始终低于HashSet
,Dictionary
或List
。即使使用BinarySearch
,对于大型集合来说也不会更快,但对于小型集合,它值得尝试。我有几百件物品,所以我传了这个。答案 2 :(得分:23)
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设置了语义,通过内部哈希表实现:
集合是一个包含no的集合 重复元素,以及其元素 没有特别的顺序。
如果HashSet失去索引/位置/列表行为,它会获得什么?
从HashSet添加和检索项总是由对象本身,而不是通过索引器,并且接近O(1)操作(List是O(1)add,O(1)通过索引检索,O( n)查找/删除)。
通过仅添加/删除键作为值,并且忽略字典值本身,可以将HashSet的行为与使用Dictionary<TKey,TValue>
进行比较。您可能希望字典中的键不具有重复值,这就是“Set”部分的重点。
答案 3 :(得分:14)
在List上选择HashSet是一个糟糕的理由。相反,有什么更好地捕捉你的意图?如果顺序很重要,那么Set(或HashSet)就会出局。如果允许重复,同样。但是在很多情况下我们不关心秩序,而且我们宁愿没有重复 - 那就是你想要一套。
答案 4 :(得分:11)
HashSet是由散列实现的 set 。集合是不包含重复元素的值的集合。集合中的值通常也是无序的。所以不,一个集不能用来替换列表(除非你首先应该使用一个集合)。
如果你想知道一个集合可能有什么用处:你想要摆脱重复的地方,显然。作为一个有点人为的例子,假设您有一个包含10,000个软件项目修订版的列表,并且您想知道有多少人为该项目做出了贡献。您可以使用Set<string>
并迭代修订列表,并将每个修订版的作者添加到集合中。一旦你完成迭代,集合的大小就是你要找的答案。
答案 5 :(得分:7)
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”};
答案 6 :(得分:6)
对于散列集最常见的用法可能是看它们是否包含某个元素,它接近于对它们的O(1)操作(假设具有足够强的散列函数),而不是检查包含的列表是O(n)(以及它是O(log n)的有序集合)。因此,如果您进行了大量检查,某个项目是否包含在某个列表中,则hahssets可能会提高性能。如果你只是迭代它们,那就没有太大区别了(迭代整个集合是O(n),与列表和hashsets相同,在添加项目时有更多的开销)。
不,你不能索引一个集合,无论如何都没有意义,因为集合没有被排序。如果你添加一些项目,那么集合将不会记住哪一个是第一个,哪个是等等。
答案 7 :(得分:4)
HashSet<T>
是.NET框架中的一个数据结构,它能够将mathematical set表示为一个对象。在这种情况下,它使用哈希码(每个项的GetHashCode
结果)来比较集合元素的相等性。
一个集合与列表的不同之处在于它只允许在其中包含一个相同元素。如果您尝试添加第二个相同的元素,HashSet<T>
将返回false
。实际上,元素的查找非常快(O(1)
时间),因为内部数据结构只是一个哈希表。
如果您想知道使用哪个,请注意使用List<T>
HashSet<T>
是合适的并不是最大的错误,尽管它可能会导致您的收藏中有不受欢迎的重复项目的问题。更重要的是,查找(项目检索)效率更高 - 理想情况下O(1)
(完美的分组)而非O(n)
时间 - 这在许多情况下非常重要。
答案 8 :(得分:4)
List<T>
用于存储有序的信息集。如果您知道列表元素的相对顺序,则可以在固定时间内访问它们。但是,要确定元素在列表中的位置或检查列表中是否存在元素,查找时间是线性的。另一方面,HashedSet<T>
不保证存储数据的顺序,因此为其元素提供了恒定的访问时间。
顾名思义,HashedSet<T>
是实现set semantics的数据结构。数据结构经过优化,可以实现集合操作(即Union,Difference,Intersect),而传统的List实现无法有效地完成这些操作。
因此,选择使用哪种数据类型实际上取决于您尝试对应用程序执行的操作。如果您不关心元素在集合中的排序方式,并且只想创建或检查是否存在,请使用HashSet<T>
。否则,请考虑使用List<T>
或其他合适的数据结构。
答案 9 :(得分:1)
简而言之 - 无论何时你想要使用一个Dictionary(或一个S是T属性的字典),你应该考虑一个HashSet(或HashSet +在T上实现IEquatable,等同于S)
答案 10 :(得分:0)
在基本的预期方案中,如果您要对两个集合进行比LINQ更复杂的设置操作,则应使用| store | newid | amount | total |
| ----- | ----- | ------ | ----- |
| 123 | 123 | 12.3 | 1 |
| 456 | 123 | 45.6 | 2 |
| 789 | adsf | 78.9 | 3 |
| 321 | 123f | | |
| 789 | 1654 | | |
。在大多数情况下,像HashSet<T>
,Distinct
,Union
和Intersect
这样的LINQ方法就足够了,但是有时您可能需要更细粒度的操作,并且Except
提供了:
HashSet<T>
UnionWith
IntersectWith
ExceptWith
SymmetricExceptWith
Overlaps
IsSubsetOf
IsProperSubsetOf
IsSupersetOf
IsProperSubsetOf
LINQ和SetEquals
“重叠”方法之间的另一个区别是LINQ总是返回新的HashSet<T>
,而IEnumerable<T>
方法修改了源集合。