CodeGym /课程 /C# SELF /集合的修改和转换

集合的修改和转换

C# SELF
第 29 级, 课程 3
可用

1. 引言

操作集合不仅仅是遍历、过滤和排序。其实经常会遇到要修改或者重做这些集合,让它们更适合你的需求:比如把字符串集合变成数字集合、从列表里去掉重复项,或者直接换个数据结构。

这些事都能用集合的标准方法、简单循环和基础算法搞定。虽然比LINQ写起来长点,但这样更透明,也有助于你理解集合的工作原理。

修改集合的主要方式

改集合的方法挺多,最常用的其实就这几种:

  • 内容修改:添加、删除或者替换元素。
  • 元素转换:拿原始集合,基于它生成一个新的——结构、类型或者形式都可以变(比如从List<int>变成List<string>)。
  • 改变表现形式:重构集合,比如排序、反转(reverse)或者分组。

我们主要关注前两种,因为排序在另一节课里已经详细讲过了。

可变集合和不可变集合:一个重要细节

要记住,.NET里有些集合可以随便改(比如List<T>),有些就不行(IReadOnlyList<T>、只读修饰的数组等等)。

  • 修改——直接改原集合(比如用Add、Remove、Clear等方法)。
  • 转换——不动原集合,生成一个新集合,通常是新建一个列表,然后把原集合的元素加进去。

2. 集合内容的修改

所有实现了ICollection<T>的集合,都有基础的方法来改内容。我们用书籍目录举个例子。

添加和删除元素

public class Book
{
    public string Title { get; set; }
    public string Author { get; set; }
    public int Year { get; set; }
}

List<Book> books = new List<Book>
{
    new Book { Title = "代码整洁之道", Author = "罗伯特·马丁", Year = 2008 },
    new Book { Title = "CLR via C#", Author = "杰弗瑞·里克特", Year = 2012 }
};

// 添加新书
books.Add(new Book { Title = "Head First C#", Author = "安德鲁·斯特尔曼", Year = 2010 });

// 按条件删除书(比如按作者)
for (int i = books.Count - 1; i >= 0; i--)
{
    if (books[i].Author == "罗伯特·马丁")
        books.RemoveAt(i);
}

// 删除指定对象(如果在列表里有)
Book someBook = books[0];
books.Remove(someBook);

// 清空整个集合
books.Clear();

// 在指定位置插入元素
books.Insert(0, new Book { Title = "Pro C# 9", Author = "安德鲁·特罗尔森", Year = 2021 });

替换和更新元素

比如,有人把出版年份写错了,怎么改?

// 用循环找到那本书,改年份
for (int i = 0; i < books.Count; i++)
{
    if (books[i].Title == "Head First C#")
    {
        books[i].Year = 2018; // 改了年份
        break;
    }
}

3. 集合的转换

元素类型转换(比如从Book变成字符串)

获取所有书名的集合:

List<string> bookTitles = new List<string>();
foreach (Book book in books)
{
    bookTitles.Add(book.Title);
}

foreach (var title in bookTitles)
{
    Console.WriteLine(title);
}

获取所有书的年份:

List<int> bookYears = new List<int>();
foreach (Book book in books)
{
    bookYears.Add(book.Year);
}

转换成新类型/结构:

public class BriefBookInfo
{
    public string Title;
    public int Year;
}

List<BriefBookInfo> briefInfos = new List<BriefBookInfo>();
foreach (Book book in books)
{
    briefInfos.Add(new BriefBookInfo { Title = book.Title, Year = book.Year });
}

foreach (var info in briefInfos)
{
    Console.WriteLine($"{info.Title} ({info.Year})");
}

把集合的集合拍平成一个(flat map)

如果一本书有标签列表,怎么拿到所有标签的总列表:

public class Book
{
    public string Title { get; set; }
    public List<string> Tags { get; set; }
}

List<Book> booksWithTags = new List<Book>
{
    new Book { Title = "代码整洁之道", Tags = new List<string> { "Clean Code", "Refactoring" } },
    new Book { Title = "CLR via C#", Tags = new List<string> { "CLR", "Internals" } }
};

List<string> allTags = new List<string>();
foreach (var book in booksWithTags)
{
    foreach (var tag in book.Tags)
    {
        allTags.Add(tag);
    }
}

foreach (string tag in allTags)
{
    Console.WriteLine(tag);
}

4. 常用的集合转换方法

ToArray

想把列表变成数组:

string[] bookTitlesArray = bookTitles.ToArray();

Distinct——去重

唯一作者(不用LINQ):

List<string> authors = new List<string>();
foreach (Book book in books)
{
    if (!authors.Contains(book.Author))
        authors.Add(book.Author);
}

Reverse——反转集合

想把顺序反过来:

books.Reverse(); // 直接原地改!

如果不想动原集合:

var reversed = new List<Book>(books);
reversed.Reverse();

排序(详见排序讲座)

books.Sort((a, b) => a.Year.CompareTo(b.Year)); // 按年份排序

按字段分组(模拟GroupBy)

按作者分组书籍(得到“作者—书列表”的字典):

Dictionary<string, List<Book>> booksByAuthor = new Dictionary<string, List<Book>>();
foreach (Book book in books)
{
    if (!booksByAuthor.ContainsKey(book.Author))
        booksByAuthor[book.Author] = new List<Book>();
    booksByAuthor[book.Author].Add(book);
}

foreach (var pair in booksByAuthor)
{
    Console.WriteLine($"作者: {pair.Key}");
    foreach (var b in pair.Value)
        Console.WriteLine($"  {b.Title}");
}

5. 有用的小细节

  • 用循环做转换,在哪都能用,绝对靠谱。
  • 想去重,就用临时集合和Contains/Add方法。
  • 别在foreach遍历时改集合!要删很多元素,先单独收集要删的,再删。

6. 常见任务示例

获取某一年以后的书列表

List<Book> recentBooks = new List<Book>();
foreach (Book book in books)
{
    if (book.Year > 2010)
        recentBooks.Add(book);
}
foreach (var book in recentBooks)
{
    Console.WriteLine($"{book.Title} ({book.Year})");
}

输出所有出版年份(去重后升序)

List<int> years = new List<int>();
foreach (Book book in books)
{
    if (!years.Contains(book.Year))
        years.Add(book.Year);
}
years.Sort();

foreach (int year in years)
    Console.WriteLine(year);

准备书籍导出(生成DTO列表)

public class BookExport
{
    public string Name;
    public string Writer;
    public int PublishedYear;
}

List<BookExport> booksForExport = new List<BookExport>();
foreach (Book book in books)
{
    booksForExport.Add(new BookExport
    {
        Name = book.Title,
        Writer = book.Author,
        PublishedYear = book.Year
    });
}

7. 常见错误和坑

像Add、Remove、Clear、Insert和Sort这些方法,都是直接改集合本身的。

如果你想要新集合——就新建一个列表,把需要的元素加进去。

遍历集合时要删元素,记得用倒序遍历(for (int i = Count-1; i >= 0; i--))。

要唯一元素的列表,注意别加重复的:用Contains或者HashSet<T>。

2
任务
C# SELF, 第 29 级, 课程 3
已锁定
在集合中添加、删除和修改元素
在集合中添加、删除和修改元素
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION