TOC

This article is currently in the process of being translated into Russian (~99% done).

LINQ:

Filtering data: the Where() method

Одна из базовых (а также наиболее мощных) операций, которую вы можете выполнять с наборами данных - это фильтрация. Мы уже видели, что можно делать с медотом Where() в вводной статье о LINQ. В этой статье мы познакомимся с этим методом более углубленно. Мы уже обсуждали какие LINQ методы могут использовать лямбда выражения для выполнения своих задач и метод Where() - один из таких. Этот метод принимает каждый элемент множества на вход и затем выполняет логику, котора решает включать этот элемент в результирующее множество или исключить. Вот простой пример:

List<int> numbers = new List<int>()
{
    1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n < 10);
foreach (var n in smallNumbers)
    Console.WriteLine(n);

В этом примере, каждое число проверяется нашим условным выржением, которое вызвращает true, если чилсо меньше 10 и false, если оно больше или равно 10. В результате, мы получим версию оригинального списка, где включены числа меньше 10, которые затем будут выведены на консоль.

Однако, выражение не обязательно должно быть таким простым, как в этом примере. Мы можем добавить больше логики к нему, как например мы делаем в if-конструкциях.

List<int> numbers = new List<int>()
{
    1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n > 1 && n != 4 &&  n < 10);
foreach (var n in smallNumbers)
    Console.WriteLine(n);

Мы указываем, что число должно быть больше 1 и меньше 10, исключая значение 4.

Конечно, вы также можете использовать выражения с вызовом различных методов, которые возвращают логические значения так, что метод Where() знает какие значения включать в результат, а какие пропускать. Вот пример:

List<int> numbers = new List<int>()
{
    1, 2, 4, 7, 8, 16, 29, 32, 64, 128
};
List<int> excludedNumbers = new List<int>()
{
    7, 29
};
var validNumbers = numbers.Where(n => !excludedNumbers.Contains(n));
foreach (var n in validNumbers)
    Console.WriteLine(n);

В этом примере мы определяем второй числовой список - список нежелательных чисел, которые не должны попасть в результат! В методе Where() мы используем метод Contains() по нежелательному списку значений, чтобы решить, следует ли включить число в результирующий список или нет.

Конечно, это работает и для более сложных объектов, чем числа и строки, и это очень просто использовать. Просто взгляните на следующий пример, где мы используем объекты с информацией о пользователях вместо чисел, применяя метод Where() чтобы получить список пользователей, чьи имена начинаются с буквы "J" и возраст которых не старше 39 лет:

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqWhere2
{
    class Program
    {
static void Main(string[] args)
{
    List<User> listOfUsers = new List<User>()
    {
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 34 },
new User() { Name = "Joe Doe", Age = 8 },
new User() { Name = "Another Doe", Age = 15 },
    };

    var filteredUsers = listOfUsers.Where(user => user.Name.StartsWith("J") && user.Age < 40);
    foreach (User user in filteredUsers)
Console.WriteLine(user.Name + ": " + user.Age);
}


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

}
    }
}

И для сравнения, здесь синтаксис вызова, основанный на запросе вместо вызова метода:

// Method syntax
var filteredUsers = listOfUsers.Where(user => user.Name.StartsWith("J") && user.Age < 40);

// Query syntax
var filteredUsersQ = from user in listOfUsers where user.Name.StartsWith("J") && user.Age < 40 select user;

Несколько последовательных вызовов Where()

Мы уже кратко обсуждали это в введении в LINQ: окончательный результат выражения LINQ не вычисляется до тех пор, пока он не нужен фактически, например, вам нужно обработать результат в цикле, подсчитать количество элементов или последовательно обработать все элементы (как мы делаем в примерах). Это так же значит, что допустимо соединять несколько вызовов метода Where() в цепочку в случае очень сложных выражений, если так их будет удобнее читать. Ниже исправленная версия нашего предыдущего примера:

List<int> numbers = new List<int>()
{
    1, 2, 4, 8, 16, 32
};
var smallNumbers = numbers.Where(n => n > 1).Where(n => n != 4).Where(n => n < 10);
foreach (var n in smallNumbers)
    Console.WriteLine(n);

Результат в точности тот же самый, и, хотя первая версия не выглядит достаточно сложной, чтобы разбить её на несколько вызовов метода Where(), вы, скорее всего, столкнётесь со случаями, когда это будет иметь смысл. Я хочу подчеркнуть, что это не добавит дополнительных затрат на вычисление с точки зрения производительности, потому что реальное вычисление результата не производится до тех пор, пока мы не используем результат в цикле. К этому моменту компилятор и интерпретатор уже оптимизируют вашу цепочку вызовов для максимально быстрого вычисления и способ записи этих вызовов не важен.

Итоги

С помощью метода Where() вы можете легко отфильтровать ненужные элементы из входных данных и создать подмножество исходных данных. Помните, что вы на самом деле получаете новый набор данных, а исходный источник данных останется неизменным, если только вы специально не переопределите исходную переменную.


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!