Агрегаты и ToList
Подсчитывайте, суммируйте и материализуйте данные
«Агрегаты и ToList» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Подсчёт элементов
Count возвращает количество элементов в последовательности. С условием он подсчитывает только подходящие элементы.
Этот оператор принудительно запускает перебор, поэтому для получения итога обрабатывается вся последовательность — это операция агрегирования.
using System;
using System.Linq;
int[] nums = { 1, 2, 3, 4, 5 };
Console.WriteLine(nums.Count());
Console.WriteLine(nums.Count(n => n > 2));Суммирование значений
Sum складывает числовые значения. Для числовой последовательности он суммирует элементы, а с селектором — выбранное значение каждого элемента.
Результат имеет тот же числовой тип, что и источник или результат селектора.
using System;
using System.Linq;
using System.Collections.Generic;
record Order(int Qty, decimal Price);
var orders = new List<Order> { new(2, 5m), new(3, 4m) };
decimal total = orders.Sum(o => o.Qty * o.Price);
Console.WriteLine(total);Вычисление среднего значения
Average вычисляет среднее арифметическое. Как и Sum, он принимает необязательный селектор.
Результат имеет тип с плавающей точкой, например double, даже если источник содержит целые числа, поэтому при делении точность не теряется.
using System;
using System.Linq;
int[] scores = { 80, 90, 100 };
double avg = scores.Average();
Console.WriteLine(avg);Минимум и максимум
Min и Max возвращают наименьшее и наибольшее значения. С селектором они выбирают минимальный или максимальный ключ из преобразованных данных.
В современных версиях .NET MaxBy и MinBy возвращают весь элемент с экстремальным ключом, а не только значение ключа.
using System;
using System.Linq;
using System.Collections.Generic;
record P(string Name, int Age);
var ps = new List<P> { new("Ana", 30), new("Bo", 22) };
var oldest = ps.MaxBy(p => p.Age);
Console.WriteLine(oldest!.Name);Проблемы с пустой последовательностью
Для пустой последовательности Average, Min и Max над типами-значениями выбрасывают исключение InvalidOperationException. Sum возвращает ноль, а Count — ноль.
Проверяйте данные с помощью Any() или используйте DefaultIfEmpty перед вычислением среднего для потенциально пустых данных.
using System;
using System.Linq;
int[] empty = Array.Empty<int>();
double avg = empty.DefaultIfEmpty(0).Average();
Console.WriteLine(avg);Aggregate для пользовательских свёрток
Aggregate сворачивает последовательность в одно значение с помощью функции накопления. Это общий вариант операций, лежащих в основе Sum и других операторов.
Вы можете задать начальное значение и объединять с ним каждый элемент, получая промежуточный результат. Это удобно для вычисления произведений, объединения строк и пользовательской логики.
using System;
using System.Linq;
int[] nums = { 1, 2, 3, 4 };
int product = nums.Aggregate(1, (acc, n) => acc * n);
Console.WriteLine(product);Материализация с помощью ToList
ToList немедленно выполняет запрос и копирует результаты в объект List<T>. Это намеренно прекращает отложенное выполнение.
Используйте его, чтобы получить стабильный снимок данных, не запускать ресурсоёмкий конвейер повторно или воспользоваться возможностями списка, например индексацией и свойством Count.
using System;
using System.Linq;
int[] nums = { 1, 2, 3, 4 };
var evens = nums.Where(n => n % 2 == 0).ToList();
evens.Add(6);
Console.WriteLine(string.Join(", ", evens));ToArray и ToDictionary
К связанным методам материализации относятся ToArray для массива фиксированного размера и ToDictionary для поиска по ключу.
ToDictionary принимает селектор ключа и необязательный селектор значения, а затем выбрасывает исключение, если два элемента дают один и тот же ключ.
using System;
using System.Linq;
using System.Collections.Generic;
record P(string Name, int Age);
var ps = new List<P> { new("Ana", 30), new("Bo", 22) };
var byName = ps.ToDictionary(p => p.Name, p => p.Age);
Console.WriteLine(byName["Ana"]);Зачем материализовать данные
Отложенные запросы запускаются заново при каждом переборе. Если конвейер ресурсоёмкий или читает изменяющийся источник, это приводит к ошибкам и замедлению работы.
Однократный вызов ToList сохраняет результаты, поэтому последующие чтения выполняются быстро и дают согласованные данные.
using System;
using System.Linq;
int runs = 0;
int[] nums = { 1, 2, 3 };
var list = nums.Select(n => { runs++; return n; }).ToList();
foreach (var _ in list) { }
foreach (var _ in list) { }
Console.WriteLine(runs);First, один элемент и Any
Операторы получения элементов также запускают выполнение. First возвращает первое совпадение и выбрасывает исключение, если совпадений нет; FirstOrDefault вместо этого возвращает значение по умолчанию, а Single требует ровно один элемент.
Any сообщает, есть ли в последовательности хотя бы один подходящий элемент, не перебирая все элементы для подсчёта.
using System;
using System.Linq;
int[] nums = { 3, 8, 5, 12 };
int firstBig = nums.First(n => n > 7);
bool hasOdd = nums.Any(n => n % 2 == 1);
Console.WriteLine($"{firstBig} {hasOdd}");Полный конвейер
В реальных запросах объединяются фильтрация, формирование нужной структуры данных, сортировка и агрегирование, часто с завершением методом материализации.
Читайте запрос сверху вниз: отфильтруйте данные, сформируйте их структуру, отсортируйте и соберите результат. Итоговый ToList запускает весь конвейер один раз.
using System;
using System.Linq;
using System.Collections.Generic;
record Sale(string City, int Amt);
var sales = new List<Sale> { new("NY", 5), new("LA", 3), new("NY", 9) };
var top = sales.Where(s => s.Amt > 4)
.OrderByDescending(s => s.Amt)
.Select(s => s.City)
.ToList();
Console.WriteLine(string.Join(", ", top));Быстрая проверка
Подумайте об отложенном выполнении и материализации.
Повторение
Агрегаты сводят последовательность к одному значению: Count, Sum, Average, Min/Max, MinBy/MaxBy и общий Aggregate. Они запускают выполнение и могут выбрасывать исключения для пустых источников.
ToList, ToArray и ToDictionary материализуют результаты, прекращая отложенное выполнение, поэтому ресурсоёмкий конвейер запускается один раз. На этом завершается набор инструментов LINQ для фильтрации и формирования результатов.
Часто задаваемые вопросы
Урок «Агрегаты и ToList» бесплатный?
Да — полный текст урока «Агрегаты и ToList» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Агрегаты и ToList»?
Подсчитывайте, суммируйте и материализуйте данные Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Агрегаты и ToList»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- WHERE и фильтрация
- SELECT и проекция
- OrderBy и группировка
- Агрегаты и ToList