Наша RPG-игра вышла в релиз, и серверы накопили огромный объём данных: списки игроков, логи сражений, инвентари, таблицы рекордов. Руководство хочет аналитику: кто из игроков набрал больше 1000 очков? Какие предметы самые популярные? Сколько сражений выиграл каждый маг?
У нас есть список игроков в виде List<Player>. Нужно отобрать только тех, у кого очки больше 1000, и отсортировать их по убыванию.
Задача: Напишите код, который из списка игроков выберет тех, у кого Score > 1000, отсортирует по убыванию очков и выведет их имена.
До сих пор для работы с коллекциями мы использовали циклы: foreach для перебора, if для фильтрации, временные списки для накопления результатов. Это работает, но при сложных запросах код быстро превращается в кашу из вложенных циклов и условий. LINQ предлагает другой подход.
Вот как выглядит решение задачи из «Разведки боем» с помощью LINQ:
using System;
using System.Linq; // Подключаем LINQ
using System.Collections.Generic;
class Player
{
public string Name { get; set; }
public int Score { get; set; }
public string Class { get; set; } // Маг, Воин, Лучник
}
class Program
{
static void Main()
{
var players = new List<Player>
{
new Player { Name = "Альберт", Score = 2500, Class = "Маг" },
new Player { Name = "Эдвард", Score = 800, Class = "Воин" },
new Player { Name = "Мерлин", Score = 3100, Class = "Маг" },
new Player { Name = "Элиза", Score = 1200, Class = "Лучник" },
new Player { Name = "Фёдор", Score = 500, Class = "Воин" },
};
var topPlayers = players
.Where(p => p.Score > 1000) // Фильтрация
.OrderByDescending(p => p.Score) // Сортировка
.ToList();
foreach (var p in topPlayers)
Console.WriteLine($"{p.Name}: {p.Score}");
}
}
Три строки вместо десяти. Нет временных коллекций, нет ручной сортировки. Код читается почти как обычный текст: «из игроков выбери тех, у кого очки больше 1000, отсортируй по убыванию».
Если цикл
foreach— это ручная сборка на конвейере (берёшь деталь, проверяешь, кладёшь в нужную коробку), то LINQ — это заказ на складе: «мне нужны все детали типа А, отсортированные по размеру». Склад сам разберётся, как выполнить заказ. LINQ работает с любым типом, реализующим интерфейсIEnumerable<T>. На практике это означает — с любой коллекцией:
| Коллекция | Работает с LINQ? |
|---|---|
List<T> |
Да |
Array (T[]) |
Да |
Dictionary<K,V> |
Да (перебирает KeyValuePair) |
HashSet<T> |
Да |
string |
Да (перебирает char) |
Чтобы использовать LINQ, нужно подключить пространство имён:
using System.Linq;
LINQ-методы можно выстраивать в цепочку — каждый метод принимает коллекцию и возвращает новую:
var result = players
.Where(p => p.Score > 1000) // Из 5 игроков осталось 3
.OrderByDescending(p => p.Score) // Отсортировали: 3100, 2500, 1200
.Select(p => p.Name) // Взяли только имена
.ToList(); // Материализовали в List<string>
// result: ["Мерлин", "Альберт", "Элиза"]
Каждый метод в цепочке делает одну простую вещь. Вместе они описывают сложный запрос, который легко читать сверху вниз.
LINQ (Language Integrated Query) — технология C#, позволяющая писать запросы к коллекциям в декларативном стиле. Вы описываете что хотите получить, а не как это сделать.
LINQ работает с любой коллекцией, реализующей IEnumerable<T>: списки, массивы, словари, множества.
LINQ-методы выстраиваются в цепочку, не изменяют исходную коллекцию и проверяются компилятором.
Для использования необходимо подключить using System.Linq;.