HashSet <T>和List <T>有什么区别?


156

您能解释一下.NET HashSet<T>和之间的区别List<T>吗?

也许您可以举一个例子来说明在哪种情况下HashSet<T>应优先选择List<T>




有关性能的信息,请参见hashset-vs-list-performance
nawfal 2014年

Answers:


213

与List <>不同...

  1. HashSet是一个没有重复成员的列表。

  2. 由于HashSet被限制为仅包含唯一条目,因此内部结构针对搜索(与列表相比)进行了优化-速度更快

  3. 添加到HashSet中会返回一个布尔值-如果由于Set中已存在添加而导致添加失败,则返回false

  4. 可以对Set执行以下数学运算:Union / Intersection / IsSubsetOf等。

  5. HashSet不实现IList仅ICollection

  6. 您不能将索引与HashSet一起使用,只能与枚举器一起使用。

使用HashSet的主要原因是,如果您对执行Set操作感兴趣。

给定2组:hashSet1和hashSet2

 //returns a list of distinct items in both sets
 HashSet set3 = set1.Union( set2 );

与使用LINQ的等效操作相比,它飞行得更好。写也很整洁!


IDK,我在Union方法方面遇到问题。我曾经使用过UnionWith
用户

2
+1表示“使用HashedSet的主要原因是,如果您有兴趣执行Set操作。”
LCJ 2012年

12
实际上,我更喜欢指出以下答案的答案:HashSet适合在您可以将集合视为“袋子物品”的情况下使用。设置操作不如遏制检查那么频繁。在任何时候,如果您有一组唯一的项目(例如代码),并且需要检查是否包含,则HashSet很方便。
ThunderGr

好答案。我也想添加一些性能特征差异。
nawfal 2014年

1
问题:主要原因是没有确定没有重复的项目?
Andrea Scarafoni,

54

更确切地说,让我们通过示例进行演示,

您不能像以下示例中那样使用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的有像一些有用的功能IntersectWithUnionWithIsProperSubsetOfExceptWithSymmetricExceptWith等。

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

51

A HashSet<T>是一个旨在为您O(1)提供包含查找的类(即,此集合是否包含特定对象,并快速告诉我答案)。

A List<T>是一个类,旨在为您提供具有O(1)随机访问权限的集合,并且该集合可以动态增长(请考虑动态数组)。您可以及时测试收容措施O(n)(除非列表已排序,否则您可以及时进行二进制搜索O(log n))。

也许您可以举一个例子来说明在哪种情况下HashSet<T>应优先考虑List<T>

当您想测试中的收容措施时O(1)


如果列表已排序,则为O(log n)。毕竟,它比未排序列表中的查找要快。
Andrei

20

使用List<T>时要:

  • 以一定顺序存储项目集合。

如果您知道想要的项目索引(而不是项目本身的值),则检索为O(1)。如果您不知道索引,O(n)对于未排序的集合,找到该项目会花费更多时间。

使用Hashset<T>时要:

  • 快速找出集合中是否包含某个对象。

如果您知道要查找的事物的名称,则查找为O(1)(即“哈希”部分)。它不会像这样保持顺序,List<T>并且您不能存储重复项(添加重复项无效,这是“设置”部分)。

例如,Hashset<T>如果您想找出在Scrabble游戏中玩过的单词是否是英语(或其他语言)中的有效单词,则可以使用一个示例。如果您想构建一个供此类游戏在线版本的所有实例使用的Web服务,那就更好了。

A List<T>将是一个很好的数据结构,用于创建计分板来跟踪玩家分数。


15

列表是有序列表。它是

  • 通过整数索引访问
  • 可以包含重复项
  • 具有可预测的顺序

HashSet是一个集合。它:

  • 可以阻止重复项(请参阅Add(T)
  • 不保证套装内物品的顺序
  • 具有您期望的一组操作,例如 IntersectWith,IsProperSubsetOf,UnionWith。

当您要访问集合时,就像它可以在其中添加,插入和删除项目的数组一样,访问列表更合适。如果您想将集合视为顺序不重要的项目的“袋子”,或者希望使用IntersectWith或UnionWith等操作将其与其他集合进行比较,则HashSet是更好的选择。



3

列表是T型对象的有序集合,与数组不同,您可以添加和删除条目。

您将使用一个列表,在该列表中您想按存储它们的顺序引用这些成员,并且您按职位而不是项目本身来访问它们。

HashSet就像字典一样,该项本身既是键又是值,因此无法保证顺序。

您将使用HashSet来检查对象是否在集合中


1
澄清一下,以防万一其他人乍看之下是错的- List维持顺序(即添加内容时),但不会自动对项目进行排序。您必须致电.Sort或使用SortedList
drzaus

1

如果您决定将这些数据结构应用于数据驱动的开发中的实际使用情况,则HashSet对于根据数据适配器源测试复制以进行数据清理和迁移非常有帮助。

同样,如果使用DataAnnotations类,则可以在类属性上实现键逻辑,并使用HashSet有效地控制自然索引(是否聚集),这在List实现中非常困难。

使用列表的一个强大选择是在视图模型上为多种媒体实现泛型,例如将类列表发送到DropDownList Helper的MVC视图,以及通过WebApi作为JSON构造发送。该列表允许典型的类收集逻辑,并为使用类似“接口”的方法为不同媒介计算单个视图模型保留了灵活性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.