你能解释一下.NET中HashSet<T>
和List<T>
之间的区别吗?
也许您可以通过一个示例来解释HashSet<T>
应该首选哪些List<T>
?
感谢。
答案 0 :(得分:192)
与List&lt;&gt;不同...
HashSet是一个没有重复成员的列表。
由于HashSet被限制为仅包含唯一条目,因此内部结构已针对搜索进行了优化(与列表进行比较) - 速度相当快
添加到HashSet会返回一个布尔值 - 如果添加因Set中已存在而失败,则返回false 。)可以对Set:Union / Intersection / IsSubsetOf等执行数学集合运算。
HashSet不实现仅IList ICollection
您不能将索引与HashSet一起使用,只能使用枚举数。
使用HashSet的主要原因是您有兴趣执行Set操作。
给定2组:hashSet1和hashSet2
//returns a list of distinct items in both sets
HashSet set3 = set1.Union( set2 );
与使用LINQ的等效操作相比,飞得很快。写作也更整洁!
答案 1 :(得分:49)
HashSet<T>
是一个专门用于O(1)
查找包含的类(即,此集合是否包含特定对象,并快速告诉我答案)。
List<T>
是一个类,旨在为您提供一个O(1)
随机访问的集合,而不是动态增长(想想动态数组)。您可以在O(n)
时间内测试包含(除非对列表进行排序,然后您可以在O(log n)
时间内进行二进制搜索。)
也许您可以通过一个示例来解释
HashSet<T>
应该优先考虑List<T>
如果您想在O(1)
中测试遏制。
答案 2 :(得分:47)
更准确地说,举例说明,
您不能像以下示例中那样使用HashSet。
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);
hashSet1[i]
会产生错误:
无法将带有[]的索引应用于类型的表达式 'System.Collections.Generic.HashSet'
您可以使用foreach语句:
foreach (var item in hashSet1)
Console.WriteLine(item);
您无法将重复项添加到HashSet,而List允许您执行此操作 当您向HashSet添加项目时,可以检查它是否包含该项目。
HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
if (hashSet1.Add("1"))
Console.WriteLine("'1' is successfully added to hashSet1!");
else
Console.WriteLine("'1' could not be added to hashSet1, because it contains '1'");
HashSet有一些有用的功能,如IntersectWith
,UnionWith
,IsProperSubsetOf
,ExceptWith
,SymmetricExceptWith
等。
IsProperSubsetOf
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
HashSet<string> hashSet3 = new HashSet<string>() { "1", "2", "3", "4", "5" };
if (hashSet1.IsProperSubsetOf(hashSet3))
Console.WriteLine("hashSet3 contains all elements of hashSet1.");
if (!hashSet1.IsProperSubsetOf(hashSet2))
Console.WriteLine("hashSet2 does not contains all elements of hashSet1.");
UnionWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" };
hashSet1.UnionWith(hashSet2); //hashSet1 -> 3, 2, 4, 6, 8
IntersectWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
HashSet<string> hashSet2 = new HashSet<string>() { "2", "4", "6", "8" }
hashSet1.IntersectWith(hashSet2);//hashSet1 -> 4, 8
ExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.ExceptWith(hashSet2);//hashSet1 -> 5, 6
SymmetricExceptWith
:
HashSet<string> hashSet1 = new HashSet<string>() { "1", "2", "3", "5", "6" };
HashSet<string> hashSet2 = new HashSet<string>() { "1", "2", "3", "4" };
hashSet1.SymmetricExceptWith(hashSet2);//hashSet1 -> 4, 5, 6
顺便说一下,订单不会保留在HashSets中。在示例中,我们最后添加了元素“2”,但它是第二个顺序:
HashSet<string> hashSet1 = new HashSet<string>() { "3", "4", "8" };
hashSet1.Add("1"); // 3, 4, 8, 1
hashSet1.Remove("4"); // 3, 8, 1
hashSet1.Add("2"); // 3, 2 ,8, 1
答案 3 :(得分:18)
在您想要的时候使用List<T>
:
如果您知道所需项目的索引(而不是项目本身的值),则检索为O(1)
。如果您不知道索引,则查找该项目需要更多时间,O(n)
用于未排序的集合。
在您想要的时候使用Hashset<T>
:
如果您知道要查找的内容的名称,则查找为O(1)
(这是“哈希”部分)。它不像List<T>
那样保持排序,你不能存储重复项(添加副本没有效果,那就是'Set'部分)。
何时使用Hashset<T>
的示例是,如果您想知道在Scrabble游戏中播放的单词是否是英语(或其他语言)中的有效单词。如果您想构建一个Web服务,以供这种游戏的在线版本的所有实例使用,那就更好了。
List<T>
是一个很好的数据结构,用于创建记分板以跟踪玩家得分。
答案 4 :(得分:13)
列表是一个有序列表。它是
HashSet是一个集合。它:
当您想要访问集合时,列表更合适,就像它可以追加,插入和删除项目的数组一样。如果您希望将您的集合视为“包”中的顺序不重要的项目,或者您希望使用IntersectWith或UnionWith等操作将其与其他集进行比较,则HashSet是更好的选择。
答案 5 :(得分:3)
List是T类对象的有序集合,与您可以添加和删除条目的数组不同。
您将使用一个列表,您希望按照存储它们的顺序引用成员,并且您通过位置而不是项目本身访问它们。
HashSet就像一个字典,项目本身就是关键和价值,订单无法保证。
您可以使用HashSet来检查对象是否在集合中
答案 6 :(得分:2)
列表不一定是唯一的,而hashset是一个。
答案 7 :(得分:0)
如果您决定将这些数据结构应用于数据驱动开发中的实际使用,则HashSet在测试针对数据适配器源的复制,数据清理和迁移方面非常有用。
此外,如果使用DataAnnotations类,可以在类属性上实现Key逻辑,并使用HashSet有效地控制自然索引(无论是否聚簇),这在List实现中非常困难。
使用列表的一个强大选项是在视图模型上实现多个媒体的泛型,例如将类列表发送到DropDownList Helper的MVC视图,以及通过WebApi作为JSON构造发送。该列表允许典型的类集合逻辑,并保持更多&#34;接口&#34;就像将单个视图模型计算到不同介质的方法一样。