如何使用 C# 中的 HashSet

译文链接:

https://www.infoworld.com/article/3586972/how-to-use-hashset-in-csharp.html

HashSet 是一个优化过的无序集合,提供对元素的高速查找和高性能的set集合操作,而且 HashSet 是在 .NET 3.5 中被引入的,在 System.Collection.Generic 命名空间下

要运行本篇文章的案例代码,需要安装一下 Visual Studio 2019,如果没有的话可以到官网下载一下。

使用 VS 创建一个 .NET Core 控制台程序

首先,我通过 VS2019 创建一个 .NET Core 控制台程序,创建可以参考下面步骤:
打开 Visual Studio IDE
点击创建 Create new project 在 Create new project 窗口上,
从模板列表中选择:Console App(.NET Core)
点击下一步 在 Configure your new project 界面填好你的项目名称和存放路径
.
这样我们就创建好了一个新项目,本文的后面部分就会在这个项目里来给大家分享 HashSet 的一些必备知识。

HashSet 到底是什么

所谓的HashSet,指的就是 System.Collections.Generic 命名空间下的 HashSet 类,它是一个高性能,无序的集合,因此HashSet它并不能做排序操作,也不能包含任何重复的元素,Hashset 也不能像数组那样使用索引,所以在 HashSet 上你无法使用 for 循环,只能使用 foreach 进行迭代,HashSet 通常用在处理元素的唯一性上有着超高的性能。

HashSet 实现了如下几个接口:

public class HashSet<T> : System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>, 
System.Collections.Generic.IReadOnlyCollection<T>,
System.Collections.Generic.ISet<T>,
System.Runtime.Serialization.IDeserializationCallback,
System.Runtime.Serialization.ISerializable
{
    
    
}

HashSet 只能包含唯一的元素,它的内部结构也为此做了专门的优化,值得注意的是,HashSet 也可以存放单个的 null 值,可以得出这么一个结论:如何你想拥有一个具有唯一值的集合,那么 HashSet 就是你最好的选择,何况它还具有超高的检索性能。

从 HashSet 中查找一个元素

如果想判断某一个元素是否在 HashSet 内,建议使用 Contains 进行判断,代码如下:

static void Main(string[] args)
    {
    
    
        HashSet<string> hashSet = new HashSet<string>();
        hashSet.Add("A");
        hashSet.Add("B");
        hashSet.Add("C");
        hashSet.Add("D");
        if (hashSet.Contains("D"))
            Console.WriteLine("The required element is available.");
        else
            Console.WriteLine("The required element isn’t available.");
        Console.ReadKey();
    }

HashSet中的元素唯一性

如果你向 HashSet 中插入重复的元素,它的内部会忽视这次操作而不像别的集合一样抛出异常,接下来展示一下代码:

 static void Main(string[] args)
    {
    
    
        HashSet<string> hashSet = new HashSet<string>();
        hashSet.Add("A");
        hashSet.Add("B");
        hashSet.Add("C");
        hashSet.Add("D");
        hashSet.Add("D");
        Console.WriteLine("The number of elements is: {0}", hashSet.Count);
        Console.ReadKey();
    }

当你执行了这个程序,输出结果如下:

The number of elements is:4

现在可以考虑一下下面的代码段,它展示了重复的元素是如何被剔除的。

static void Main(string[] args)
    {
    
    
        string[] cities = new string[] {
    
    
            "Delhi",
            "Kolkata",
            "New York",
            "London",
            "Tokyo",
            "Washington",
            "Tokyo"
        };
        HashSet<string> hashSet = new HashSet<string>(cities);
        foreach (var city in hashSet)
        {
    
    
            Console.WriteLine(city);
        }
    }

当你执行完上面的程序,重复的城市名称已经被移除了。

Delhi
Kolkata
New York
London
Tokyo
Washington

从 HashSet 中移除元素

从HashSet 中删除某一个元素可以调用 Remove 方法,它的语法结构如下:

public bool Remove (T item);

如果在集合中找到了这个元素,Remove方法将会删除这个元素并且返回true,否则返回 false。

下面的代码片段展示了如何使用 Remove 方法删除 HashSet 中的元素

string item = "D";
if(hashSet.Contains(item))
{
    
    
   hashSet.Remove(item);
}

如果你想删除 HashSet 中的所有元素,可以调用 Clear 方法。

HashSet 的 set操作
HashSet提供了非常多的方法用于 set集合 操作上,比如说:IntersectWith, UnionWith, IsProperSubsetOf, ExceptWith, 和 SymmetricExceptWith

IsProperSubsetOf

这个 IsProperSubsetOf 用于判断 HashSet 是否为某一个集合的完全子集,可以看下面的例子:

HashSet<string> setA = new HashSet<string>() {
    
     "A", "B", "C", "D" };
HashSet<string> setB = new HashSet<string>() {
    
     "A", "B", "C", "X" };
HashSet<string> setC = new HashSet<string>() {
    
     "A", "B", "C", "D", "E" };
if (setA.IsProperSubsetOf(setC))
   Console.WriteLine("setC contains all elements of setA.");
if (!setA.IsProperSubsetOf(setB))
   Console.WriteLine("setB does not contains all elements of setA.");

如果你执行了上面这个程序,你会在控制台上看到如下的输出:

setC contains all elements of setA.
setB does not contains all elements of setA.

UnionWith

UnionWith方法常用于集合的合并,比如说下面的代码:

HashSet<string> setA = new HashSet<string>() {
    
     "A", "B", "C", "D", "E" };
HashSet<string> setB = new HashSet<string>() {
    
     "A", "B", "C", "X", "Y" };
setA.UnionWith(setB);
foreach(string str in setA)
{
    
    
   Console.WriteLine(str);
}

当你执行完上面的代码,SetB 集合会被 SetA 集合吞掉,最后 SetA 集合将会是包括:“A”, “B”, “C”, “D”, “E”, “X”, and “Y” 。

IntersectWith

IntersectWith 方法常用于表示两个 HashSet 的交集,下面的例子或许会让你更加理解:

HashSet<string> setA = new HashSet<string>() {
    
     "A", "B", "C", "D", "E" };
HashSet<string> setB = new HashSet<string>() {
    
     "A", "X", "C", "Y"};
setA.IntersectWith(setB);
foreach (string str in setA)
{
    
    
    Console.WriteLine(str);
}

当你运行了上面的这段程序,只有两个 HashSet 中都存在的元素才会输出到控制台中,输出结果如下所示:

A
C

ExceptWith

ExceptWith 方法表示数学上的减法操作,这个时间复杂度是 O(N),假定你有两个HashSet 集合,分别叫 setA 和 setB,并且用了下面的语句。

setA.ExceptWith(setB);

它返回的元素为:setA中有,setB中没有 的最终结果,如果还不明白的话,使用如下代码辅助理解:

HashSet<string> setA = new HashSet<string>() {
    
     "A", "B", "C", "D", "E" };
HashSet<string> setB = new HashSet<string>() {
    
     "A", "X", "C", "Y" };
setA.ExceptWith(setB);
foreach (string str in setA)
{
    
    
   Console.WriteLine(str);
}

当你执行了上面这段程序,元素 B,D,E 将会输出到控制台上。

SymmetricExceptWith

SymmetricExceptWith 方法常用于修改一个 HashSet 来存放两个 HashSet 都是唯一的元素,换句话说,我要的就是两个集合都不全有的元素,如果还不明白的话,考虑下面的代码段:

HashSet<string> setA = new HashSet<string>() {
    
     "A", "B", "C", "D", "E" };
HashSet<string> setB = new HashSet<string>() {
    
     "A", "X", "C", "Y" };
setA.SymmetricExceptWith(setB);
foreach (string str in setA)
{
    
    
  Console.WriteLine(str);
}

当你执行完上面的代码,你会发现,setA中有而setB中没有 和 setB中有而setA中没有的元素将会输出到控制台中。

X
B
Y
D
E

我们知道数组的平均复杂度是 O(N),这里的 n 表示数组里的元素数量,而访问 HashSet 中的某一个元素,它的复杂度为 O(1),这个常量复杂度就决定了 HashSet 在快速检索 和执行 set集合 操作上是一个非常好的选择,你也可以使用 List 去存储某些有指定顺序的元素,同时也可以包含重复的值。

猜你喜欢

转载自blog.csdn.net/weixin_38531633/article/details/120304211