JavaRush /Курсы /C# SELF /Фильтрация элементов

Фильтрация элементов

C# SELF
29 уровень , 0 лекция
Открыта

1. Базовые способы фильтрации коллекций

Фильтрация — это как сито для золота, только вместо самородков мы отбираем из коллекции только те элементы, которые нам нужны. Например, есть у нас список пользователей — хочется найти только совершеннолетних, или только студентов, или только тех, кто любит кофе (программистов, короче). Выборка подходящих элементов — это очень частая задача, которая встречается везде: от работы с БД до обработки пользовательского ввода.

Давайте рассмотрим разные способы фильтрации в C#. По мере изучения будем развивать наше учебное консольное приложение, добавляя в него фильтры.

Ручная фильтрация с помощью цикла

Начнем с самого простого и классического способа: фильтрации с помощью foreach:


// Пример: есть список чисел, нужно выбрать только чётные

List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> evenNumbers = new List<int>();

foreach (int number in numbers)
{
    if (number % 2 == 0) // если число чётное
    {
        evenNumbers.Add(number);
    }
}

Console.WriteLine("Чётные числа:");
foreach (int n in evenNumbers)
{
    Console.WriteLine(n);
}

Такой способ работает всегда, его легко понять, но он не самый компактный и не самый "современный".

Почему ручная фильтрация не всегда удобна?

Когда у вас появляется другая коллекция, другой критерий фильтрации, или вам нужно писать сразу несколько фильтров — получится много похожего кода. Хочется компактности, читаемости и модульности.

2. Фильтрация по сложным критериям

Допустим, у нас есть коллекция объектов. Возьмём пример с пользователями из нашего развиваемого приложения.


public class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public bool IsStudent { get; set; }
}

Объявляем список пользователей:


List<User> users = new List<User>
{
    new User { Name = "Аня", Age = 17, IsStudent = true },
    new User { Name = "Борис", Age = 21, IsStudent = false },
    new User { Name = "Вика", Age = 19, IsStudent = true },
    new User { Name = "Глеб", Age = 25, IsStudent = false }
};

Пример 1: Выбрать всех студентов


List<User> students = new List<User>();
foreach (User user in users)
{
    if (user.IsStudent)
        students.Add(user);
}

Console.WriteLine("Список студентов:");
foreach (User user in students)
{
    Console.WriteLine($"{user.Name} ({user.Age})");
}

Пример 2: Выбрать совершеннолетних студентов


List<User> adults = new List<User>();
foreach (User user in users)
{
    if (user.Age >= 18 && user.IsStudent)
        adults.Add(user);
}

Console.WriteLine("Совершеннолетние студенты:");
foreach (User user in adults)
{
    Console.WriteLine($"{user.Name} ({user.Age})");
}

А если критерии фильтрации динамические?

Можно выносить условия фильтрации в отдельные методы, чтобы вызывать их внутри цикла:


bool IsAdult(User u) { return u.Age >= 18; }
bool IsStudent(User u) { return u.IsStudent; }

List<User> filtered = new List<User>();
foreach (User user in users)
{
    if (IsAdult(user) && IsStudent(user))
        filtered.Add(user);
}

3. Фильтрация по ключу в словарях

Списки и массивы — это удобно, но часто мы работаем и со словарями.

Допустим, у нас есть словарь, где ключ — имя пользователя, а значение — его возраст:


Dictionary<string, int> ageByName = new Dictionary<string, int>
{
    ["Аня"] = 17,
    ["Борис"] = 21,
    ["Вика"] = 19,
    ["Глеб"] = 25
};

Задача: выбрать только пользователей 18+


Dictionary<string, int> adults = new Dictionary<string, int>();
foreach (var pair in ageByName)
{
    if (pair.Value >= 18)
        adults.Add(pair.Key, pair.Value);
}

Console.WriteLine("Совершеннолетние:");
foreach (var pair in adults)
{
    Console.WriteLine($"{pair.Key}: {pair.Value} лет");
}

Задача: выбрать пользователей с именами на букву "В"


Dictionary<string, int> namesWithV = new Dictionary<string, int>();
foreach (var pair in ageByName)
{
    if (pair.Key.StartsWith("В"))
        namesWithV.Add(pair.Key, pair.Value);
}

Console.WriteLine("Имёна на букву 'В':");
foreach (var pair in namesWithV)
{
    Console.WriteLine($"{pair.Key}: {pair.Value} лет");
}

4. Принципы фильтрации

Как работает процесс фильтрации


┌──────────────────────────────────┐
│  Список: [1, 2, 3, 4, 5, 6]      │
└──────────────────────────────────┘
         │
         ▼
    [Проверка: n % 2 == 0]
         │
         ▼
┌──────────────────────────────────┐
│  Результат: [2, 4, 6]            │
└──────────────────────────────────┘

Композиция фильтров: фильтруем по разным условиям

Можно делать последовательные фильтрации, если хочется поэтапно отбирать данные:


// Сначала фильтруем только студентов
List<User> onlyStudents = new List<User>();
foreach (User user in users)
{
    if (user.IsStudent)
        onlyStudents.Add(user);
}

// Потом выбираем среди них только совершеннолетних
List<User> adultStudents = new List<User>();
foreach (User user in onlyStudents)
{
    if (user.Age >= 18)
        adultStudents.Add(user);
}

Или всё сразу:


List<User> adultStudents = new List<User>();
foreach (User user in users)
{
    if (user.IsStudent && user.Age >= 18)
        adultStudents.Add(user);
}

Сортировка и другие операции

Сортировку можно делать с помощью метода Sort для списков:


// Совершеннолетние студенты, отсортированные по возрасту
adultStudents.Sort((a, b) => a.Age.CompareTo(b.Age));

Подробнее о сортировке поговорим на следующей лекции!

5. Фильтрация в пользовательских сценариях

1. Фильтрация ввода пользователя

Допустим, наше приложение принимает список оценок и должно выбрать все "пятёрки".


Console.Write("Введите оценки через пробел: ");
string input = Console.ReadLine();

List<int> grades = new List<int>();
foreach (string s in input.Split(' '))
{
    if (int.TryParse(s, out int grade))
        grades.Add(grade);
}

List<int> fives = new List<int>();
foreach (int grade in grades)
{
    if (grade == 5)
        fives.Add(grade);
}

Console.WriteLine("Пятёрки:");
foreach (var grade in fives)
{
    Console.WriteLine(grade);
}

2. Фильтрация по множеству условий

Задача: выбрать пользователей-студентов в возрасте от 18 до 22 лет включительно.


List<User> filtered = new List<User>();
foreach (User user in users)
{
    if (user.IsStudent && user.Age >= 18 && user.Age <= 22)
        filtered.Add(user);
}

3. Фильтрация по наличию элемента

Пусть у нас есть список строк, и мы хотим выбрать только те, которые содержат подстроку ".net" (без учёта регистра).


List<string> technologies = new List<string> { "C#", ".NET", "Java", "dotnet", "JavaScript" };

List<string> netTechs = new List<string>();
foreach (var tech in technologies)
{
    if (tech.ToLower().Contains(".net"))
        netTechs.Add(tech);
}

foreach (var tech in netTechs)
{
    Console.WriteLine(tech);
}

6. Особенности и типичные ошибки при фильтрации

Фильтрация кажется простой, но здесь можно наломать дров. Давайте разберём некоторые особенности.

Изменение исходной коллекции

Если вы фильтруете исходную коллекцию, а затем меняете её содержимое после фильтрации, — результат не изменится, если вы уже создали новый список. Если же вы только запомнили ссылку на старый список, изменения в исходной коллекции могут повлиять на итог.


List<int> filtered = new List<int>();
foreach (int n in numbers)
{
    if (n > 2)
        filtered.Add(n);
}

// Внесём изменение в исходный список
numbers.Add(10);

foreach (var n in filtered)
{
    Console.WriteLine(n); // 10 не попадёт сюда
}

Результат ручной фильтрации

Результатом ручной фильтрации обычно является новый изменяемый список (например, List<T>), с которым можно делать всё, что нужно — добавлять, удалять элементы и т.д.

Фильтрация и производительность

Фильтры в циклах вызываются для каждого элемента коллекции, так что если функция внутри условия тяжёлая — будьте осторожны. Иногда проще сделать простой цикл foreach, особенно если есть сложная логика и требуется логирование или дополнительные действия.

2
Задача
C# SELF, 29 уровень, 0 лекция
Недоступна
Фильтрация словаря по значениям
Фильтрация словаря по значениям
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ