C# - 数组
现代 C# - 数组与集合
Section titled “现代 C# - 数组与集合”在 C# 中,数组(Array)是一种基础数据结构,它存储固定大小的、同类型元素的有序集合。可以将其想象成一个带编号的盒子列表,每个盒子存放同一种物品,并且可以通过其编号(或索引)进行访问。数组在内存中是连续存储的,这使得通过索引访问元素非常快速。
虽然你可以声明 score1、score2、score3 等单独的变量,但使用数组 scores 会效率得多。然后,你可以使用索引访问单个元素,例如 scores[0]、scores[1] 和 scores[2]。请注意,C# 中的数组索引是从零开始的,这意味着第一个元素位于索引 0。
声明和初始化数组
Section titled “声明和初始化数组”通过指定元素类型,后跟方括号 [] 来声明数组。初始化是分配内存并提供初始值的过程。
以下是声明和初始化数组的常见方式:
// 1. 声明并初始化一个特定大小的数组(元素会获得默认值,例如 int 为 0)int[] numbers = new int[5];
// 2. 声明并使用值进行初始化(编译器推断大小)double[] balances = { 2340.0, 4523.69, 3421.0 };
// 3. 使用 'new' 关键字和初始化器列表string[] names = new string[] { "Alice", "Bob", "Charlie" };
// 4. 使用目标类型 'new' 表达式(C# 9 及更高版本)char[] vowels = new[] { 'a', 'e', 'i', 'o', 'u' };当你创建一个数组时,C# 会将每个元素初始化为其默认值。对于数值类型,默认值是 0;对于 bool 类型,是 false;对于引用类型(如 string),是 null。
访问和修改数组元素
Section titled “访问和修改数组元素”你可以使用方括号内的从零开始的索引来访问和修改数组元素。
string[] names = { "Alice", "Bob", "Charlie" };
// 访问第一个元素string firstName = names[0]; // "Alice"
// 修改第二个元素names[1] = "Barbara";
Console.WriteLine($"The names are: {names[0]}, {names[1]}, {names[2]}");// 输出: The names are: Alice, Barbara, Charlie常见陷阱:差一错误
Section titled “常见陷阱:差一错误”一个常见的错误是尝试访问有效索引范围之外的元素。一个长度为 3 的数组,其有效索引是 0、1 和 2。访问 names[3] 将会抛出 IndexOutOfRangeException 异常。
// 这将导致运行时错误!// string errorName = names[3];循环遍历数组元素是一项常见的任务。foreach 循环是执行此操作最简单、最安全的方式。
使用 foreach(推荐)
Section titled “使用 foreach(推荐)”foreach 循环迭代集合中的每个元素,无需管理索引变量。
using System;
int[] scores = { 99, 98, 92, 97, 95 };
Console.WriteLine("Student Scores:");foreach (int score in scores){ Console.WriteLine(score);}使用 for 循环
Section titled “使用 for 循环”当你在迭代过程中需要访问元素的索引时,for 循环会很有用。
using System;
string[] fruits = { "Apple", "Banana", "Cherry" };
for (int i = 0; i < fruits.Length; i++){ Console.WriteLine($"Fruit at index {i}: {fruits[i]}");}Length 属性返回数组中元素的总数。在 for 循环中,条件 i < fruits.Length 可以防止 IndexOutOfRangeException 异常的发生。
有用的数组操作
Section titled “有用的数组操作”System.Array 类和 LINQ(Language-Integrated Query)提供了处理数组的强大方法。
你可以使用 Array.Sort() 对数组进行原地排序。
int[] numbers = { 50, 20, 40, 10, 30 };
// 按升序排序Array.Sort(numbers);
// 要按降序排序,先排序再反转Array.Reverse(numbers);
Console.WriteLine(string.Join(", ", numbers)); // 输出: 50, 40, 30, 20, 10为了获得更大的灵活性,特别是当你不想修改原始数组时,可以使用 LINQ。你需要添加 using System.Linq;。
using System.Linq;
int[] originalNumbers = { 50, 20, 40, 10, 30 };
// LINQ 方法返回一个新的序列,它们不修改原始数组var sortedAscending = originalNumbers.OrderBy(n => n).ToArray();var sortedDescending = originalNumbers.OrderByDescending(n => n).ToArray();
Console.WriteLine($"Ascending: {string.Join(", ", sortedAscending)}");Console.WriteLine($"Descending: {string.Join(", ", sortedDescending)}");将一个数组变量赋值给另一个变量并不会创建副本;两个变量都将指向内存中的同一个数组。
int[] original = { 1, 2, 3 };int[] referenceCopy = original; // 不是真正的副本
referenceCopy[0] = 99;
Console.WriteLine(original[0]); // 输出: 99要创建一个真实的、独立的副本(浅拷贝),你可以使用 LINQ 的 ToArray() 方法或 Array.Copy()。
using System.Linq;
int[] sourceArray = { 1, 2, 3, 4, 5 };
// 使用 LINQ 的现代方式int[] newCopy = sourceArray.ToArray();
// 传统方式int[] destinationArray = new int[sourceArray.Length];Array.Copy(sourceArray, destinationArray, sourceArray.Length);
newCopy[0] = 100;Console.WriteLine($"Source: {sourceArray[0]}"); // 输出: Source: 1Console.WriteLine($"New Copy: {newCopy[0]}"); // 输出: New Copy: 100数组与其它集合
Section titled “数组与其它集合”当元素数量固定时,数组在性能方面表现出色。然而,对于需要动态增长或收缩的集合,其他类型通常是更好的选择。
| 类型 | 描述 |
|---|---|
Array (int[]) | 固定大小。通过索引访问时性能最佳。当集合大小已知且不会改变时使用。 |
List (List<int>) | 动态大小。最常见的通用集合。提供 Add()、Remove() 和 Sort() 等方法。 |
Multi-dimensional Array (int[,]) | 矩形数组(例如,网格或矩阵)。所有行的长度必须相同。 |
Jagged Array (int[][]) | 数组的数组。每个内部数组可以有不同的长度。 |
对于 C# 新手,通常最好从 List<T> 开始。它比数组更灵活,并且在现代 .NET 应用程序中被广泛使用。你可以使用 .ToList() 和 .ToArray() 轻松地在 List<T> 和数组之间进行转换。