ZetCode

C# 列表

最后修改于 2025 年 5 月 14 日

本文提供了关于在 C# 中使用 List 集合的全面指南。学习如何在你的应用程序中高效地存储、管理和操作动态列表。

C# 列表

C# 中的 List 类表示一个强类型、可调整大小的对象集合,可以通过索引访问。它提供了强大的方法来动态地搜索、排序、过滤和修改列表元素,使其成为处理结构化数据的必要工具。

List 类的主要特性

常用方法和操作

List 类提供了多种操作列表的方法。以下是一些最常用的方法

方法 描述
Add(T item) 将一个元素添加到列表的末尾。
Insert(int index, T item) 在指定的索引处插入一个元素。
Remove(T item) 删除指定项的第一个匹配项。
RemoveAt(int index) 删除指定索引处的元素。
Contains(T item) 检查列表中是否存在某个元素。
IndexOf(T item) 获取指定项的第一个匹配项的索引。
Sort 按升序对列表进行排序。
Reverse 反转列表的顺序。
Clear 从列表中删除所有元素。
Count 返回列表中的元素数量。

这些方法使 List 类成为用于处理 C# 中动态集合的多功能数据结构。无论您是需要添加、删除还是重新排序元素,这些内置功能都提供了一种高效的方式来管理列表,而无需手动内存分配或复杂的操作。

C# List 初始化器

C# 列表可以使用字面量表示法进行初始化。元素在赋值的右侧,位于 {} 括号内。

Program.cs
var words = new List<string> { "forest", "oak", "river", "falcon" };
Console.WriteLine(string.Join(", ", words));

在示例中,我们使用列表初始化器创建了一个字符串列表。

var words = new List<string>{"forest", "oak", "river", "falcon"};

创建了一个新列表。在尖括号 (<>) 之间,我们指定列表元素的数据类型。

Console.WriteLine(string.Join(", ", words));

为了快速查看列表的内容,我们将所有值连接成一个字符串,用逗号分隔。

$ dotnet run
forest, oak, river, falcon

C# List 集合表达式

.NET 8 引入了一种简洁的语法来创建和初始化列表。

Program.cs
List<string> words = ["forest", "oak", "river", "falcon"];
Console.WriteLine(string.Join(", ", words));

列表的元素放置在一对方括号 ([]) 内。 这种语法被许多编程语言共享。

C# List 计数元素

使用 Count 属性,我们可以获取列表中的元素数量。

Program.cs
List<int> vals = [0, 1, 2, 3, 4, 5];
Console.WriteLine($"There are {vals.Count} elements in the list");

该示例计算列表中的元素数量。

Console.WriteLine($"There are {vals.Count} elements in the list");

这里我们打印列表中元素的数量。

$ dotnet run
There are 6 elements in the list

C# List 访问元素

可以使用索引符号 [] 访问列表的元素。 索引是从零开始的。

Program.cs
List<int> vals = [0, 1, 2, 3, 4, 5];

Console.WriteLine(vals[0]);
Console.WriteLine(vals[1]);

Console.WriteLine(vals.Count - 1);

Console.WriteLine(vals[^1]);
Console.WriteLine(vals[^2]);

该示例打印列表的第一个、第二个和最后一个元素。

Console.WriteLine(vals.Count - 1);

要获取列表的最后一个元素,我们计算元素的数量并减去一。

Console.WriteLine(vals[^1]);
Console.WriteLine(vals[^2]);

使用 ^ 运算符,我们可以从列表的末尾访问元素。

$ dotnet run
0
1
5
5
4

C# List 添加元素

Add 方法在列表的末尾添加一个元素。 AddRange 方法将指定集合的元素添加到列表的末尾。

Program.cs
List<string> words = ["forest", "oak", "river", "falcon"];

words.Add("sky");
words.Add("ocean");

string[] words2 = ["owl", "hawk"];
words.AddRange(words2);

Console.WriteLine(string.Join(',', words));

该示例创建两个列表并向其中添加新元素。

words.Add("sky");
words.Add("ocean");

使用 Add 向列表添加了两个元素。

string[] words2 = ["owl", "hawk"];
words.AddRange(words2);

使用 AddRange 方法,我们将另一个集合添加到列表中。

$ dotnet run
forest,oak,river,falcon,sky,ocean,owl,hawk

C# List 插入元素

Insert 方法在指定索引处将一个元素插入到列表中。 InsertRange 在指定索引处将集合的元素插入到列表中。

Program.cs
List<string> words = ["forest", "oak", "river", "falcon"];

words.Insert(0, "sky");
words.Insert(words.Count, "cloud");

List<string> words2 =["water", "wave"];
words.InsertRange(2, words2);

Console.WriteLine(string.Join(", ", words));

该示例创建一个新单词列表并将新元素插入到其中。

$ dotnet run
sky, forest, water, wave, oak, river, falcon, cloud

C# List Contains

Contains 方法确定元素是否在列表中。

Program.cs
List<string> words =  ["forest", "oak", "river", "falcon"];

if (words.Contains("oak"))
{
    Console.WriteLine("The list contains the oak word");
}

在该示例中,我们检查 oak 单词是否在列表中。

C# List 删除元素

可以使用 RemoveRemoveAtRemoveAllRemoveRangeClear 方法从列表中删除元素。

Program.cs
List<int> nums = [0, 1, 2, -3, 4, -5, 6, 7, -8, 9, 10];

nums.RemoveAll(e => e < 0);
Console.WriteLine(string.Join(", ", nums));

nums.Remove(0);
nums.RemoveAt(nums.Count - 1);

Console.WriteLine(string.Join(", ", nums));

nums.RemoveRange(0, 3);

Console.WriteLine(string.Join(", ", nums));

nums.Clear();
Console.WriteLine("{0}", nums.Count);

在该示例中,我们从整数列表中删除元素。

nums.RemoveAll(e => e < 0);
Console.WriteLine(string.Join(", ", nums));

使用 RemoveAll 方法,我们删除所有满足给定谓词的元素;在我们的例子中,我们删除所有负值。

nums.Remove(0);

Remove 方法删除 0 值的第一个匹配项。

nums.RemoveAt(nums.Count - 1);

使用 RemoveAt,我们删除给定索引处的元素。

nums.RemoveRange(0, 3);

RemoveRange 方法从列表中删除给定范围的值。 参数是要删除的元素范围的从零开始的起始索引以及要删除的元素数量。

C# List ToArray

ToArray 方法将列表的元素复制到数组中。

Program.cs
List<int> nums = [1, 2, 3, 4];

Console.WriteLine(nums.GetType());

var nums2 = nums.ToArray();
Console.WriteLine(nums2.GetType());

在该示例中,我们从列表创建一个数组。 我们使用 GetType 打印两个容器的类型。

$ dotnet run
System.Collections.Generic.List`1[System.Int32]
System.Int32[]

C# List ForEach

ForEach 方法对列表的每个元素执行指定的操作。

Program.cs
List<string> words = ["forest", "oak", "river", "falcon"];

words.ForEach(Console.WriteLine);
words.ForEach(word => Console.WriteLine(word.ToUpper()));

我们在单词列表上调用 ForEach 方法两次。

words.ForEach(Console.WriteLine);

我们打印列表的所有元素。

words.ForEach(word => Console.WriteLine(word.ToUpper()));

这里我们也打印列表的所有元素; 这些单词被转换为大写。

$ dotnet run
forest
oak
river
falcon
FOREST
OAK
RIVER
FALCON

C# 循环 List

有几种方法可以循环遍历 C# 列表。

Program.cs
List<int> nums = [1, 2, 3, 4];

nums.ForEach(e => Console.WriteLine(e));

Console.WriteLine("********************");

foreach (int e in nums)
{

    Console.WriteLine(e);
}

Console.WriteLine("********************");

for (int i = 0; i < nums.Count; i++)
{

    Console.WriteLine(nums[i]);
}

该示例显示了在 C# 中循环遍历列表的三种方法。

nums.ForEach(e => Console.WriteLine(e));

我们使用 ForEach 循环遍历列表。

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

在这种情况下,我们使用 foreach 语句。

for (int i = 0; i < nums.Count; i++)
{
    Console.WriteLine(nums[i]);
}

最后,这是经典的 for 循环。

$ dotnet run
1
2
3
4
********************
1
2
3
4
********************
1
2
3
4

C# 排序、反转 List

Sort 方法对列表的元素进行排序,Reverse 方法反转列表的元素。

Program.cs
List<int> nums = [2, 1, 5, 4, 3];

nums.Reverse();
Console.WriteLine(string.Join(',', nums));

nums.Sort();
Console.WriteLine(string.Join(',', nums));

该示例反转整数列表的元素,然后对它们进行排序。

$ dotnet run
3,4,5,1,2
1,2,3,4,5

C# List FindAll

FindAll 方法检索列表中所有符合指定谓词定义的条件的元素。 如果找到,它将返回一个包含所有符合指定谓词定义的条件的元素的列表;否则,返回一个空列表。

谓词是一种返回布尔值的方法。 要了解有关谓词的更多信息,请访问C# 谓词教程

Program.cs
List<int> vals = [-1, -3, 0, 1, 3, 2, 9, -4];
List<int> filtered = vals.FindAll(e => e > 0);

Console.WriteLine(string.Join(',', filtered));

该示例查找所有正元素。

List<int> filtered = vals.FindAll(e => e > 0);

谓词是一个表达式,对于大于零的值返回 true。

$ dotnet run
1,3,2,9

这些是列表的正值。

C# List Find, FindLast, FindIndex, FindLastIndex

Find 方法返回与给定谓词匹配的元素的第一个匹配项。 FindLast 方法返回与给定谓词匹配的元素的最后一个匹配项。

FindIndex 方法返回与给定谓词匹配的元素的第一个匹配项的索引。 FindLastIndex 方法返回与给定谓词匹配的元素的最后一个匹配项的索引。

Program.cs
List<int> nums = [6, -2, 1, 5, 4, 3, 2, 9, -1, 7];

var found = nums.Find(e => e < 0);
Console.WriteLine(found);

var found2 = nums.FindIndex(e => e < 0);
Console.WriteLine(found2);

var found3 = nums.FindLast(e => e < 0);
Console.WriteLine(found3);

var found4 = nums.FindLastIndex(e => e < 0);
Console.WriteLine(found4);

该示例使用所有提到的方法来查找元素和索引。

$ dotnet run
-2
1
-1
8

C# List ConvertAll

ConvertAll 方法将当前 List 中的元素转换为另一种类型,并返回一个包含转换后的元素的列表。

Program.cs
List<string> words = ["falcon", "owl", "sky", "hawk", "stork"];

List<string> uppedWords = words.ConvertAll(s => s.ToUpper());
List<int> lengths = words.ConvertAll(s => s.Length);

Console.WriteLine(string.Join(", ", uppedWords));
Console.WriteLine(string.Join(", ", lengths));

在该示例中,我们有一个单词列表。 我们将该列表转换为另外两个列表。

List<string> uppedWords = words.ConvertAll(s => s.ToUpper());

这里我们将列表转换为包含转换为大写的单词的列表。

List<int> lengths = words.ConvertAll(s => s.Length);

在第二种情况下,转换后的列表包含整数,这些整数是原始列表中单词的长度。

$ dotnet run
FALCON, OWL, SKY, HAWK, STORK
6, 3, 3, 4, 5

在第二个示例中,我们有一个单独的 squareRoot 方法,该方法应用于整数列表。

Program.cs
double squareRoot(int x)
{
    return Math.Sqrt(x);
}

List<int> vals = [1, 4, 9, 16, 25];

Converter<int, double> converter = squareRoot;
List<double> vals2 = vals.ConvertAll(converter);

Console.WriteLine(string.Join(", ", vals2));

在该示例中,我们通过对整数列表应用平方根运算来创建一个新列表。

$ dotnet run
1, 2, 3, 4, 5

C# List 洗牌

以下示例随机重建整数值列表。

Program.cs
List<int> vals = [1, 2, 3, 4, 5, 6, 7, 8];
vals.Shuffle();

var res = string.Join(" ", vals);
Console.WriteLine(res);

static class MyExtensions
{
    private static readonly Random rng = new();

    public static void Shuffle<T>(this IList<T> vals)
    {
        int n = vals.Count;

        while (n > 1)
        {
            n--;
            int k = rng.Next(n + 1);

            (vals[n], vals[k]) = (vals[k], vals[n]);
        }
    }
}

在该示例中,我们创建一个 Shuffle 扩展方法。 它会就地打乱元素。

public static void Shuffle<T>(this IList<T> vals)
{
    int n = vals.Count;

    while (n > 1)
    {
        n--;
        int k = rng.Next(n + 1);

        (vals[n], vals[k]) = (vals[k], vals[n]);
    }
}

这是 Fisher-Yates 洗牌算法的实现。

$ dotnet run
7 1 5 6 4 2 3 8
$ dotnet run
7 5 4 1 2 3 6 8
$ dotnet run
2 3 8 5 1 4 7 6
$ dotnet run
4 5 1 6 8 2 3 7

C# List TrueForAll

TrueForAll 确定列表中的每个元素是否都符合给定谓词定义的条件。

Program.cs
List<int> nums = [1, 2, 3, 4, 5, 6, 7, 8];

var res1 = nums.TrueForAll(e => e % 2 == 0);
Console.WriteLine(res1);

var res2 = nums.TrueForAll(e => e > 0);
Console.WriteLine(res2);

在该示例中,我们检查列表中的元素是否都是偶数以及它们是否都是正数。

$ dotnet run
False
True

并非所有元素都是偶数,并且所有元素都是正数。

LINQ

语言集成查询 (LINQ)是一组技术的名称,这些技术基于将查询功能直接集成到 C# 语言中。

通过 LINQ,C# 公开了大量用于处理 List 数据的方法。

C# List 聚合计算

LINQ 具有扩展方法来计算聚合计算,例如最小、最大或总和。

Program.cs
List<int> vals = [-1, 2, 1, -3, 7, -9, 5, 9, -4, 8];

var n1 = vals.Count;
Console.WriteLine($"There are {n1} elements");

var n2 = vals.Count(e => e % 2 == 0);
Console.WriteLine($"There are {n2} even elements");

var sum = vals.Sum();
Console.WriteLine($"The sum of all values is: {sum}");

var s2 = vals.Sum(e => e > 0 ? e : 0);
Console.WriteLine($"The sum of all positive values is: {s2}");

var avg = vals.Average();
Console.WriteLine($"The average of values is: {avg}");

var max = vals.Max();
Console.WriteLine($"The maximum value is: {max}");

var min = vals.Min();
Console.WriteLine($"The minimum value is: {min}");

在该程序中,我们使用 Count、Sum、Average、Max 和 Min 方法。

$ dotnet run
There are 10 elements
There are 3 even elements
The sum of all values is: 15
The sum of all positive values is: 32
The average of values is: 1.5
The maximum value is: 9
The minimum value is: -9

C# List 排序

要对数据进行排序,我们可以使用 OrderByThenBy 扩展方法。 请注意,这些方法会创建一个新的修改列表;原始列表不会更改。

Program.cs
List<User> users =
[
    new ("John", "Doe", 1230),
    new ("Lucy", "Novak", 670),
    new ("Ben", "Walter", 2050),
    new ("Robin", "Brown", 2300),
    new ("Amy", "Doe", 1250),
    new ("Joe", "Draker", 1190),
    new ("Janet", "Doe", 980),
    new ("Albert", "Novak", 1930),
];

Console.WriteLine("sort ascending by last name and salary");

var sortedUsers = users.OrderBy(u => u.LastName).ThenBy(u => u.Salary);

foreach (var user in sortedUsers)
{
    Console.WriteLine(user);
}

Console.WriteLine("---------------------");

Console.WriteLine("sort descending by last name and salary");

var sortedUsers2 = users.OrderByDescending(u => u.LastName)
    .ThenByDescending(u => u.Salary);

foreach (var user in sortedUsers2)
{
    Console.WriteLine(user);
}

record User(string FirstName, string LastName, int Salary);

我们有一个用户列表。 用户首先按姓氏排序,然后按薪水排序。

var sortedUsers = users.OrderBy(u => u.LastName).ThenBy(u => u.Salary);

我们按用户的姓氏排序,然后按他们的薪水按升序排序。

var sortedUsers2 = users.OrderByDescending(u => u.LastName)
    .ThenByDescending(u => u.Salary);

在这里,我们按用户的姓氏,然后按他们的薪水进行降序排序。

$ dotnet run
sort ascending by last name and salary
User { FirstName = Robin, LastName = Brown, Salary = 2300 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Amy, LastName = Doe, Salary = 1250 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
User { FirstName = Albert, LastName = Novak, Salary = 1930 }
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
---------------------
sort descending by last name and salary
User { FirstName = Ben, LastName = Walter, Salary = 2050 }
User { FirstName = Albert, LastName = Novak, Salary = 1930 }
User { FirstName = Lucy, LastName = Novak, Salary = 670 }
User { FirstName = Joe, LastName = Draker, Salary = 1190 }
User { FirstName = Amy, LastName = Doe, Salary = 1250 }
User { FirstName = John, LastName = Doe, Salary = 1230 }
User { FirstName = Janet, LastName = Doe, Salary = 980 }
User { FirstName = Robin, LastName = Brown, Salary = 2300 }

C# List 使用 Distinct 删除重复项

Distinct 方法从列表中删除重复的元素。

Program.cs
List<int> nums = [1, 2, 2, 3, 4, 4, 5];

var unique = nums.Distinct().ToList();
Console.WriteLine(string.Join(", ", unique));

此示例使用 LINQ 中的 Distinct 方法从列表中删除重复元素。 生成的列表仅包含原始列表中的唯一值。

C# List 容量和 TrimExcess

Capacity 属性获取或设置 List 可以包含的元素数量。 如果该数字小于当前容量的 90%,则 TrimExcess 方法会将容量设置为列表中的实际元素数量。

Program.cs
List<int> vals = new List<int>(100);
Console.WriteLine($"Initial capacity: {vals.Capacity}");

vals.AddRange([1, 2, 3, 4, 5]);
Console.WriteLine($"Count: {vals.Count}");
vals.TrimExcess();
Console.WriteLine($"Trimmed capacity: {vals.Capacity}");

此示例演示了如何检查和设置列表的容量。 TrimExcess 方法减少容量以匹配元素的实际数量,这有助于优化内存使用。

C# List 二进制搜索

BinarySearch 方法在排序后的列表中搜索指定的元素,并返回该元素在列表中的从零开始的索引。 如果未找到该元素,则返回一个负数。 在调用此方法之前,必须对列表进行排序。

Program.cs
List<int> nums = [1, 3, 5, 7, 9];
int idx = nums.BinarySearch(5);

Console.WriteLine(idx); // prints 2

此示例演示了如何使用 BinarySearch 方法查找排序列表中元素的索引。 如果找到该元素,则返回其索引;否则,返回一个负数。

C# List ConvertAll:字符串到整数

ConvertAll 方法可用于将一种类型的列表转换为另一种类型。

Program.cs
List<string> numbers = ["1", "2", "3", "4"];
List<int> ints = numbers.ConvertAll(int.Parse);

Console.WriteLine(string.Join(", ", ints));

此示例使用 ConvertAll 将表示数字的字符串列表转换为整数列表。 每个字符串都解析为一个整数。

来源

List 类 - 语言参考

在本文中,我们探讨了 C# List 集合的功能,学习了如何在 .NET 应用程序中高效地存储、管理和操作动态列表。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程