JavaRush /Курсы /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 лекция
Недоступна
Добавление, удаление и модификация элементов в коллекции
Добавление, удаление и модификация элементов в коллекции
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ