HashSet < T > 和 List < T > 的区别是什么?

你能解释一下在.NET 中 HashSet<T>List<T>的区别吗?

也许你可以用一个例子来解释在什么情况下 HashSet<T>应该优先于 List<T>

93508 次浏览

列表不一定是唯一的,而散列是唯一的。

与列表不同。

  1. HashSet 是没有重复成员的 List。

  2. 因为 HashSet 被限制只包含唯一的条目,所以内部结构被优化用于搜索(与列表相比)——它相当快

  3. 如果因为 Set 中已经存在而添加失败,则向 HashSet 添加将返回 boolean-false

  4. 可以对 Set: Union/Intersect/IsSubsetOf 等执行数学集操作。

  5. HashSet 不仅实现了 IList,还实现了 ICollection

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

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

给定两组: hashSet1和 hashSet2

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

与使用 LINQ 的等效操作相比,它也更容易写!

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

List<T>是一个类,设计用于提供具有 O(1)随机访问权限的集合,这种访问权限可以动态增长(想想动态数组)。您可以在 O(n)时间内测试容器(除非列表已排序,否则可以在 O(log n)时间内执行二进制搜索)。

也许你可以用一个例子来解释在什么情况下 HashSet<T>应该优先于 List<T>

当您想在 O(1)中测试容器时。

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

您将使用一个列表,其中您希望按照存储成员的顺序引用这些成员,并且通过位置而不是项本身来访问它们。

HashSet 就像一个字典,项本身就是键和值,排序是不能保证的。

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

使用 List<T>当你想:

  • 按照一定的顺序存储项的集合。

如果知道所需项的索引(而不是项本身的值) ,则检索为 O(1)。如果不知道索引,则查找该项需要更多时间,对于未排序的集合,则为 O(n)

使用 Hashset<T>当你想:

  • 快速查明某个对象是否包含在集合中。

如果您知道要查找的内容的名称,那么查找就是 O(1)(即“散列”部分)。它不像 List<T>那样维护排序,也不能存储副本(添加副本没有效果,这是“ Set”部分)。

例如,如果你想知道在拼字游戏中的一个单词在英语(或其他语言)中是否有效,那么何时使用 Hashset<T>就是一个例子。如果您希望构建一个 Web 服务,以供此类游戏的在线版本的所有实例使用,那么更好的做法是。

一个 List<T>将是一个很好的数据结构创建记分板跟踪球员的分数。

列表是一个有序列表。它是

  • 通过整数索引访问
  • 可以包含副本
  • 有一个可预测的顺序

HashSet 是一个集合,它:

  • 可以阻止重复的项目(见 加(T))
  • 不保证集合中项的顺序
  • 具有对集 例如:。、 IntersectWith、 IsProperSubsetOf、 UnionWith 所期望的操作。

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

更准确地说,让我们用例子来演示,

不能像下面的示例那样使用 HashSet。

HashSet<string> hashSet1 = new HashSet<string>(){"1","2","3"};
for (int i = 0; i < hashSet1.Count; i++)
Console.WriteLine(hashSet1[i]);

hashSet1[i]会产生一个错误:

无法对类型的表达式应用带[]的索引 系统,集合,通用,哈希集

可以使用 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等。

返回文章页面

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.");

返回文章页面

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

返回文章页面

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

返回文章页面

 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

返回文章页面

 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

顺便说一下,哈希集中不保留顺序。在这个示例中,我们最后添加了元素“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

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

此外,如果使用 DataAnnotions 类,可以在类属性上实现 Key 逻辑,并使用 HashSet 有效地控制 Natural Index (聚集与否) ,这在 List 实现中会非常困难。

使用列表的一个强有力的选择是为视图模型上的多媒体实现泛型,例如将类的列表发送到 MVC View for a DropDownList Helper,以及通过 WebApi 作为 JSON 结构发送。该列表支持典型的类集合逻辑,并且保持了灵活性,可以采用更类似于“接口”的方法将单个视图模型计算到不同的媒体。