跳转至

C# 集合

原文: https://zetcode.com/lang/csharp/collections/

在本章中,我们将介绍 C# 集合。 .NET 框架为数据存储和检索提供了专门的类。 在前面的章节中,我们描述了数组。 集合是对数组的增强。

C# 中有三种不同的集合类型:

  • 标准
  • 泛型
  • 并发

标准集合可在System.Collections下找到。 它们不将元素存储为特定类型的对象,而是存储为Object类型的对象。 标准集合包括ArrayListHashtableQueueStack

The generic collections are found under System.Collections.Generic. Generic collections are more flexible and are the preferred way to work with data. Generics enhance code reuse, type safety, and performance. The generic collections include Dictionary<T, T>, List<T>, Queue<T>, SortedList<T>, and Stack<T>.

并发集合包括BlockingCollection<T>ConcurrentDictionary<T, T>ConcurrentQueue<T>ConcurrentStack<T>

泛型编程是一种计算机编程样式,其中,算法根据待指定的后来的类型编写,然后在需要作为参数提供的特定类型时实例化。 这种方法由 Ada 于 1983 年率先提出,它允许编写仅在使用时所使用的类型集不同的常见功能或类型,从而减少了重复。 (维基百科)

C# ArrayList

ArrayList是标准System.Collections命名空间的集合。 它是一个动态数组。 它提供对元素的随机访问。 添加数据后,ArrayList会自动扩展。 与数组不同,ArrayList可以保存多种数据类型的数据。 ArrayList中的元素通过整数索引访问。 索引从零开始。 ArrayList末尾的元素索引以及插入和删除操作需要花费固定的时间。 在动态数组的中间插入或删除元素的成本更高。 这需要线性时间。

Program.cs

using System;
using System.Collections;

namespace ArrayListEx
{
    class Empty { }

    class Program
    {
        static void Main(string[] args)
        {
            var data = new ArrayList();

            data.Add("Visual Basic");
            data.Add(344);
            data.Add(55);
            data.Add(new Empty());
            data.Remove(55);

            foreach (object el in data)
            {
                Console.WriteLine(el);
            }
        }
    }
}

在上面的示例中,我们创建了一个ArrayList集合。 我们添加了一些元素。 它们具有各种数据类型,字符串,整数和类对象。

using System.Collections;

为了使用ArrayList集合,我们需要使用System.Collections命名空间。

var data = new ArrayList();

创建一个ArrayList集合。

data.Add("Visual Basic");
data.Add(344);
data.Add(55);
data.Add(new Empty());
data.Remove(55);

我们使用Add()方法向数组添加四个元素。

data.Remove(55);

我们使用Remove()方法删除一个元素。

foreach(object el in data)
{
    Console.WriteLine(el);
}

我们遍历数组并将其元素打印到控制台。

$ dotnet run
Visual Basic
344
ArrayListEx.Empty

这是示例的输出。

C# List

List是可以通过索引访问的对象的强类型列表。 可以在System.Collections.Generic命名空间下找到。

Program.cs

using System;
using System.Collections.Generic;

namespace ListEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var langs = new List<string>();

            langs.Add("Java");
            langs.Add("C#");
            langs.Add("C");
            langs.Add("C++");
            langs.Add("Ruby");
            langs.Add("Javascript");

            Console.WriteLine(langs.Contains("C#"));

            Console.WriteLine(langs[1]);
            Console.WriteLine(langs[2]);

            langs.Remove("C#");
            langs.Remove("C");

            Console.WriteLine(langs.Contains("C#"));

            langs.Insert(4, "Haskell");

            langs.Sort();

            foreach (string lang in langs)
            {
                Console.WriteLine(lang);
            }
        }
    }
}

在前面的示例中,我们使用List集合。

using System.Collections.Generic;

List集合位于System.Collections.Generic命名空间中。

var langs = new List<string>();

将创建一个通用动态数组。 我们指定将使用在<>字符内指定类型的字符串。

langs.Add("Java");
langs.Add("C#");
langs.Add("C");
...

我们使用Add()方法将元素添加到列表中。

Console.WriteLine(langs.Contains("C#"));

我们使用Contains()方法检查列表是否包含特定的字符串。

Console.WriteLine(langs[1]);
Console.WriteLine(langs[2]);

我们使用索引符号访问List的第二个和第三个元素。

langs.Remove("C#");
langs.Remove("C");

我们从列表中删除两个字符串。

langs.Insert(4, "Haskell");

我们在特定位置插入一个字符串。

langs.Sort();

我们使用Sort()方法对元素进行排序。

$ dotnet run
True
C#
C
False
C++
Haskell
Java
Javascript
Ruby

这是示例的结果。

C# 集合初始值设定项

集合初始化器允许在对象创建期间为{}括号指定集合的​​元素。

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;

namespace CollectionInitializer
{
    class Program
    {
        static void Main(string[] args)
        {
            var vals = new List<int>() { 1, 2, 3, 4, 5, 6, 7 };

            int sum = vals.Sum();

            Console.WriteLine(sum);
        }
    }
}

该示例创建一个列表并打印其总和。 列表的元素在集合初始化器中指定。

$ dotnet run
28

这是输出。

C# SortedList

SortedList<T, T>表示已排序的键/值对的集合。

Program.cs

using System;
using System.Collections.Generic;

namespace SortedListEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var sorted = new SortedList<string, int>();

            sorted.Add("coins", 3);
            sorted.Add("books", 41);
            sorted.Add("spoons", 5);

            if (sorted.ContainsKey("books"))
            {
                Console.WriteLine("There are books in the list");
            }

            foreach (var pair in sorted)
            {
                Console.WriteLine(pair);
            }
        }
    }
}

该示例使用排序列表来组织项目。

var sorted = new SortedList<string, int>();

排序的列表具有字符串键和整数值。

if (sorted.ContainsKey("books"))
{
    Console.WriteLine("There are books in the list");
}

使用ContainsKey(),我们检查集合中是否有书籍。

foreach (var pair in sorted)
{
    Console.WriteLine(pair);
}

使用foreach循环,我们遍历集合并打印其对。

$ dotnet run
There are books in the list
[books, 41]
[coins, 3]
[spoons, 5]

This is the output.

C# LinkedList

LinkedList是 C# 中的通用双链表。 LinkedList仅允许顺序访问。 LinkedList允许进行固定时间的插入或移除,但只能顺序访问元素。 由于链表需要额外的存储空间以供参考,因此对于诸如字符之类的小型数据项列表来说,它们是不切实际的。 与动态数组不同,可以将任意数量的项目添加到链表(当然受内存限制)而无需重新分配,这是一项昂贵的操作。

Program.cs

using System;
using System.Collections.Generic;

namespace LinkedListEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var nums = new LinkedList<int>();

            nums.AddLast(23);
            nums.AddLast(34);
            nums.AddLast(33);
            nums.AddLast(11);
            nums.AddLast(6);
            nums.AddFirst(9);
            nums.AddFirst(7);

            LinkedListNode<int> node = nums.Find(6);
            nums.AddBefore(node, 5);

            foreach (int num in nums)
            {
                Console.WriteLine(num);
            }
        }
    }
}

这是一个LinkedList示例,其中包含一些方法。

var nums = new LinkedList<int>();

这是一个整数LinkedList

nums.AddLast(23);
...
nums.AddFirst(7);

我们使用AddLast()AddFirst()方法填充链表。

LinkedListNode<int> node = nums.Find(6);
nums.AddBefore(node, 5);

LinkedList由节点组成。 我们找到一个特定的节点,并在其之前添加一个元素。

foreach(int num in nums)
{
    Console.WriteLine(num);
}

我们正在将所有元素打印到控制台。

$ dotnet run
7
9
23
34
33
11
5
6

This is the output.

C# dictionary

dictionary,也称为关联数组,是唯一键和值的集合,其中每个键与一个值相关联。 检索和添加值非常快。 字典占用更多内存,因为每个值都有一个键。

Program.cs

using System;
using System.Collections.Generic;

namespace DictionaryEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var domains = new Dictionary<string, string>();

            domains.Add("de", "Germany");
            domains.Add("sk", "Slovakia");
            domains.Add("us", "United States");
            domains.Add("ru", "Russia");
            domains.Add("hu", "Hungary");
            domains.Add("pl", "Poland");

            Console.WriteLine(domains["sk"]);
            Console.WriteLine(domains["de"]);

            Console.WriteLine("Dictionary has {0} items",
                domains.Count);

            Console.WriteLine("Keys of the dictionary:");

            var keys = new List<string>(domains.Keys);

            foreach (string key in keys)
            {
                Console.WriteLine("{0}", key);
            }

            Console.WriteLine("Values of the dictionary:");

            var vals = new List<string>(domains.Values);

            foreach (string val in vals)
            {
                Console.WriteLine("{0}", val);
            }

            Console.WriteLine("Keys and values of the dictionary:");

            foreach (KeyValuePair<string, string> kvp in domains)
            {
                Console.WriteLine("Key = {0}, Value = {1}",
                    kvp.Key, kvp.Value);
            }
        }
    }
}

我们有一本字典,用于将域名映射到其国家名称。

var domains = new Dictionary<string, string>();

我们创建一个包含字符串键和值的字典。

domains.Add("de", "Germany");
domains.Add("sk", "Slovakia");
domains.Add("us", "United States");
...

我们将一些数据添加到字典中。 第一个字符串是键。 第二是值。

Console.WriteLine(domains["sk"]);
Console.WriteLine(domains["de"]);

在这里,我们通过它们的键检索两个值。

Console.WriteLine("Dictionary has {0} items",
    domains.Count);

我们通过引用Count属性来打印项目数。

var keys = new List<string>(domains.Keys);

foreach(string key in keys)
{
    Console.WriteLine("{0}", key);
}  

这些行从字典中检索所有键。

var vals = new List<string>(domains.Values);

foreach(string val in vals)
{
    Console.WriteLine("{0}", val);
}

这些行从字典中检索所有值。

foreach(KeyValuePair<string, string> kvp in domains)
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

最后,我们同时打印字典的键和值。

$ dotnet run
Slovakia
Germany
Dictionary has 6 items
Keys of the dictionary:
de
sk
us
ru
hu
pl
Values of the dictionary:
Germany
Slovakia
United States
Russia
Hungary
Poland
Keys and values of the dictionary:
Key = de, Value = Germany
Key = sk, Value = Slovakia
Key = us, Value = United States
Key = ru, Value = Russia
Key = hu, Value = Hungary
Key = pl, Value = Poland

这是示例的输出。

C# queue

queue是先进先出(FIFO)数据结构。 添加到队列中的第一个元素将是第一个要删除的元素。 队列可以用于处理消息出现时的消息,也可以用于消息到达时为客户服务的消息。 首先服务的是第一个客户。

Program.cs

using System;
using System.Collections.Generic;

namespace QueueEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var msgs = new Queue<string>();

            msgs.Enqueue("Message 1");
            msgs.Enqueue("Message 2");
            msgs.Enqueue("Message 3");
            msgs.Enqueue("Message 4");
            msgs.Enqueue("Message 5");

            Console.WriteLine(msgs.Dequeue());
            Console.WriteLine(msgs.Peek());
            Console.WriteLine(msgs.Peek());

            Console.WriteLine();

            foreach (string msg in msgs)
            {
                Console.WriteLine(msg);
            }
        }
    }
}

在我们的示例中,我们有一个包含消息的队列。

var msgs = new Queue<string>();

创建字符串队列。

msgs.Enqueue("Message 1");
msgs.Enqueue("Message 2");
...

Enqueue()将消息添加到队列末尾。

Console.WriteLine(msgs.Dequeue());

Dequeue()方法删除并返回队列开头的项目。

Console.WriteLine(msgs.Peek());

Peek()方法从队列中返回下一项,但不会将其从集合中删除。

$ dotnet run
Message 1
Message 2
Message 2

Message 2
Message 3
Message 4
Message 5

Dequeue()方法从集合中删除Message 1Peek()方法没有。 Message 2保留在集合中。

C# Stack

栈是后进先出(LIFO)数据结构。 添加到队列中的最后一个元素将是第一个要删除的元素。 C 语言使用栈将本地数据存储在函数中。 实现计算器时,还将使用该栈。

Program.cs

using System;

namespace StackEx
{
    class Program
    {
        static void Main(string[] args)
        {
            var myStack = new Stack<int>();

            myStack.Push(1);
            myStack.Push(4);
            myStack.Push(3);
            myStack.Push(6);
            myStack.Push(4);

            Console.WriteLine(myStack.Pop());
            Console.WriteLine(myStack.Peek());
            Console.WriteLine(myStack.Peek());

            Console.WriteLine();

            foreach (int item in myStack)
            {
                Console.WriteLine(item);
            }
        }
    }
}

上面有一个简单的栈示例。

var myStack = new Stack<int>();

创建一个Stack数据结构。

myStack.Push(1);
myStack.Push(4);
...

Push()方法将一个项目添加到栈的顶部。

Console.WriteLine(stc.Pop());

Pop()方法从栈顶部删除并返回该项目。

Console.WriteLine(myStack.Peek());

Peek()方法从栈顶部返回该项目。 它不会删除它。

$ dotnet run
4
6
6

6
3
4
1

这是程序的输出。

C# 教程的这一部分专门介绍 C# 中的集合。



回到顶部