💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# C# 集合 > 原文: [https://zetcode.com/lang/csharp/collections/](https://zetcode.com/lang/csharp/collections/) 在本章中,我们将介绍 C# 集合。 .NET 框架为数据存储和检索提供了专门的类。 在前面的章节中,我们描述了数组。 集合是对数组的增强。 C# 中有三种不同的集合类型: * 标准 * 泛型 * 并发 标准集合可在`System.Collections`下找到。 它们不将元素存储为特定类型的对象,而是存储为`Object`类型的对象。 标准集合包括`ArrayList`,`Hashtable`,`Queue`和`Stack`。 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` ```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`集合。 我们添加了一些元素。 它们具有各种数据类型,字符串,整数和类对象。 ```cs using System.Collections; ``` 为了使用`ArrayList`集合,我们需要使用`System.Collections`命名空间。 ```cs var data = new ArrayList(); ``` 创建一个`ArrayList`集合。 ```cs data.Add("Visual Basic"); data.Add(344); data.Add(55); data.Add(new Empty()); data.Remove(55); ``` 我们使用`Add()`方法向数组添加四个元素。 ```cs data.Remove(55); ``` 我们使用`Remove()`方法删除一个元素。 ```cs foreach(object el in data) { Console.WriteLine(el); } ``` 我们遍历数组并将其元素打印到控制台。 ```cs $ dotnet run Visual Basic 344 ArrayListEx.Empty ``` 这是示例的输出。 ## C# `List` `List`是可以通过索引访问的对象的强类型列表。 可以在`System.Collections.Generic`命名空间下找到。 `Program.cs` ```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`集合。 ```cs using System.Collections.Generic; ``` `List`集合位于`System.Collections.Generic`命名空间中。 ```cs var langs = new List<string>(); ``` 将创建一个通用动态数组。 我们指定将使用在`<>`字符内指定类型的字符串。 ```cs langs.Add("Java"); langs.Add("C#"); langs.Add("C"); ... ``` 我们使用`Add()`方法将元素添加到列表中。 ```cs Console.WriteLine(langs.Contains("C#")); ``` 我们使用`Contains()`方法检查列表是否包含特定的字符串。 ```cs Console.WriteLine(langs[1]); Console.WriteLine(langs[2]); ``` 我们使用索引符号访问`List`的第二个和第三个元素。 ```cs langs.Remove("C#"); langs.Remove("C"); ``` 我们从列表中删除两个字符串。 ```cs langs.Insert(4, "Haskell"); ``` 我们在特定位置插入一个字符串。 ```cs langs.Sort(); ``` 我们使用`Sort()`方法对元素进行排序。 ```cs $ dotnet run True C# C False C++ Haskell Java Javascript Ruby ``` 这是示例的结果。 ## C# 集合初始值设定项 集合初始化器允许在对象创建期间为`{}`括号指定集合的​​元素。 `Program.cs` ```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); } } } ``` 该示例创建一个列表并打印其总和。 列表的元素在集合初始化器中指定。 ```cs $ dotnet run 28 ``` 这是输出。 ## C# `SortedList` `SortedList<T, T>`表示已排序的键/值对的集合。 `Program.cs` ```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); } } } } ``` 该示例使用排序列表来组织项目。 ```cs var sorted = new SortedList<string, int>(); ``` 排序的列表具有字符串键和整数值。 ```cs if (sorted.ContainsKey("books")) { Console.WriteLine("There are books in the list"); } ``` 使用`ContainsKey()`,我们检查集合中是否有书籍。 ```cs foreach (var pair in sorted) { Console.WriteLine(pair); } ``` 使用`foreach`循环,我们遍历集合并打印其对。 ```cs $ 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` ```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`示例,其中包含一些方法。 ```cs var nums = new LinkedList<int>(); ``` 这是一个整数`LinkedList`。 ```cs nums.AddLast(23); ... nums.AddFirst(7); ``` 我们使用`AddLast()`和`AddFirst()`方法填充链表。 ```cs LinkedListNode<int> node = nums.Find(6); nums.AddBefore(node, 5); ``` `LinkedList`由节点组成。 我们找到一个特定的节点,并在其之前添加一个元素。 ```cs foreach(int num in nums) { Console.WriteLine(num); } ``` 我们正在将所有元素打印到控制台。 ```cs $ dotnet run 7 9 23 34 33 11 5 6 ``` This is the output. ## C# `dictionary` `dictionary`,也称为关联数组,是唯一键和值的集合,其中每个键与一个值相关联。 检索和添加值非常快。 字典占用更多内存,因为每个值都有一个键。 `Program.cs` ```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); } } } } ``` 我们有一本字典,用于将域名映射到其国家名称。 ```cs var domains = new Dictionary<string, string>(); ``` 我们创建一个包含字符串键和值的字典。 ```cs domains.Add("de", "Germany"); domains.Add("sk", "Slovakia"); domains.Add("us", "United States"); ... ``` 我们将一些数据添加到字典中。 第一个字符串是键。 第二是值。 ```cs Console.WriteLine(domains["sk"]); Console.WriteLine(domains["de"]); ``` 在这里,我们通过它们的键检索两个值。 ```cs Console.WriteLine("Dictionary has {0} items", domains.Count); ``` 我们通过引用`Count`属性来打印项目数。 ```cs var keys = new List<string>(domains.Keys); foreach(string key in keys) { Console.WriteLine("{0}", key); } ``` 这些行从字典中检索所有键。 ```cs var vals = new List<string>(domains.Values); foreach(string val in vals) { Console.WriteLine("{0}", val); } ``` 这些行从字典中检索所有值。 ```cs foreach(KeyValuePair<string, string> kvp in domains) { Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value); } ``` 最后,我们同时打印字典的键和值。 ```cs $ 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` ```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); } } } } ``` 在我们的示例中,我们有一个包含消息的队列。 ```cs var msgs = new Queue<string>(); ``` 创建字符串队列。 ```cs msgs.Enqueue("Message 1"); msgs.Enqueue("Message 2"); ... ``` `Enqueue()`将消息添加到队列末尾。 ```cs Console.WriteLine(msgs.Dequeue()); ``` `Dequeue()`方法删除并返回队列开头的项目。 ```cs Console.WriteLine(msgs.Peek()); ``` `Peek()`方法从队列中返回下一项,但不会将其从集合中删除。 ```cs $ dotnet run Message 1 Message 2 Message 2 Message 2 Message 3 Message 4 Message 5 ``` `Dequeue()`方法从集合中删除`Message 1`。 `Peek()`方法没有。 `Message 2`保留在集合中。 ## C# `Stack` 栈是后进先出(LIFO)数据结构。 添加到队列中的最后一个元素将是第一个要删除的元素。 C 语言使用栈将本地数据存储在函数中。 实现计算器时,还将使用该栈。 `Program.cs` ```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); } } } } ``` 上面有一个简单的栈示例。 ```cs var myStack = new Stack<int>(); ``` 创建一个`Stack`数据结构。 ```cs myStack.Push(1); myStack.Push(4); ... ``` `Push()`方法将一个项目添加到栈的顶部。 ```cs Console.WriteLine(stc.Pop()); ``` `Pop()`方法从栈顶部删除并返回该项目。 ```cs Console.WriteLine(myStack.Peek()); ``` `Peek()`方法从栈顶部返回该项目。 它不会删除它。 ```cs $ dotnet run 4 6 6 6 3 4 1 ``` 这是程序的输出。 C# 教程的这一部分专门介绍 C# 中的集合。