CodeGym /Các khóa học /C# SELF /Thay đổi và chuyển đổi collection

Thay đổi và chuyển đổi collection

C# SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Làm việc với collection không chỉ là duyệt, lọc hay sắp xếp. Rất nhiều lúc bạn cần thay đổi hoặc xử lý lại collection để nó phù hợp với nhu cầu của mình: ví dụ, lấy collection string rồi chuyển thành collection số, xoá duplicate khỏi list hoặc hoàn toàn đổi cấu trúc dữ liệu.

Tất cả những việc này đều có thể giải quyết bằng các method chuẩn của collection, vòng lặp đơn giản và thuật toán cơ bản. Cách này hơi dài hơn so với dùng LINQ, nhưng lại rất rõ ràng và giúp hiểu sâu về cách collection hoạt động.

Các cách chính để thay đổi collection

Có nhiều cách để thay đổi collection, và thường bạn sẽ cần một trong các hướng sau:

  • Thay đổi nội dung: thêm, xoá hoặc thay thế phần tử.
  • Chuyển đổi phần tử: lấy collection gốc và tạo ra collection mới — khác về cấu trúc, kiểu hoặc hình thức (ví dụ, từ List<int> thành List<string>).
  • Thay đổi cách hiển thị: xây dựng lại collection — ví dụ, sắp xếp, đảo ngược (reverse) hoặc group lại.

Mình sẽ tập trung vào hai nhóm đầu, vì sorting đã nói kỹ ở bài khác rồi.

Collection có thể thay đổi và không thể thay đổi: điểm cần chú ý

Bạn nên nhớ là một số collection trong .NET có thể thay đổi thoải mái (ví dụ List<T>), còn một số thì không (IReadOnlyList<T>, mảng chỉ đọc, v.v.).

  • Thay đổi — sửa trực tiếp collection (ví dụ qua Add, Remove, Clear v.v.).
  • Chuyển đổi — không đụng vào bản gốc, mà tạo collection mới, thường là tạo list mới rồi fill từ collection gốc.

2. Thay đổi nội dung collection

Tất cả collection implement ICollection<T> đều có các method cơ bản để sửa nội dung. Xem ví dụ với danh mục sách nhé.

Thêm và xoá phần 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 = "Sạch Code", Author = "Robert Martin", Year = 2008 },
    new Book { Title = "CLR qua C#", Author = "Jeffrey Richter", Year = 2012 }
};

// Thêm sách mới
books.Add(new Book { Title = "Head First C#", Author = "Andrew Stellman", Year = 2010 });

// Xoá sách theo điều kiện (ví dụ theo tác giả)
for (int i = books.Count - 1; i >= 0; i--)
{
    if (books[i].Author == "Robert Martin")
        books.RemoveAt(i);
}

// Xoá object cụ thể (nếu có trong list)
Book someBook = books[0];
books.Remove(someBook);

// Xoá hết collection
books.Clear();

// Chèn phần tử vào vị trí cụ thể
books.Insert(0, new Book { Title = "Pro C# 9", Author = "Andrew Troelsen", Year = 2021 });

Thay thế và cập nhật phần tử

Ví dụ ai đó nhập sai năm xuất bản. Sửa thế nào?

// Tìm sách cần sửa qua vòng lặp và sửa năm
for (int i = 0; i < books.Count; i++)
{
    if (books[i].Title == "Head First C#")
    {
        books[i].Year = 2018; // Đã sửa năm
        break;
    }
}

3. Chuyển đổi collection

Chuyển đổi kiểu phần tử (ví dụ từ Book sang string)

Lấy collection tên tất cả sách:

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

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

Lấy năm xuất bản của tất cả sách:

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

Chuyển sang kiểu/cấu trúc mới:

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})");
}

Chuyển collection các collection thành một (flat map)

Nếu mỗi sách có list tag, lấy ra list tất cả tag:

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

List<Book> booksWithTags = new List<Book>
{
    new Book { Title = "Sạch Code", Tags = new List<string> { "Clean Code", "Refactoring" } },
    new Book { Title = "CLR qua 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. Các method chuyển đổi collection hay dùng

ToArray

Để lấy mảng từ list:

string[] bookTitlesArray = bookTitles.ToArray();

Distinct — loại bỏ duplicate

Tác giả duy nhất (không dùng LINQ):

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

Reverse — đảo ngược collection

Để đảo thứ tự:

books.Reverse(); // thay đổi trực tiếp!

Nếu không muốn sửa bản gốc:

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

Sắp xếp (xem bài sorting)

books.Sort((a, b) => a.Year.CompareTo(b.Year)); // sort theo năm

Group theo field (giả lập GroupBy)

Group sách theo tác giả (lấy dictionary "tác giả — list sách"):

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($"Tác giả: {pair.Key}");
    foreach (var b in pair.Value)
        Console.WriteLine($"  {b.Title}");
}

5. Một số lưu ý hay gặp

  • Chuyển đổi bằng vòng lặp luôn chạy được ở mọi nơi.
  • Để loại duplicate, dùng collection tạm và method Contains/Add.
  • Đừng sửa collection khi đang duyệt bằng foreach! Nếu cần xoá nhiều phần tử, hãy gom chúng vào list riêng trước.

6. Ví dụ các bài toán thường gặp

Lấy list sách theo năm nhất định

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})");
}

In ra tất cả năm xuất bản duy nhất theo thứ tự tăng dần

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);

Chuẩn bị sách để export (tạo list-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. Lỗi thường gặp và bẫy

Các method như Add, Remove, Clear, InsertSort đều sửa collection trực tiếp.

Nếu bạn cần collection mới — hãy tạo list mới và add phần tử cần thiết vào đó.

Khi xoá phần tử lúc duyệt collection, hãy duyệt từ cuối lên (for (int i = Count-1; i >= 0; i--)).

Nếu cần list phần tử duy nhất, nhớ kiểm tra trùng lặp: dùng Contains hoặc HashSet<T>.

Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION