Проверка наличия и получение элементов

Последнее обновление: 14.02.2022

Ряд методов в LINQ позволяют проверить наличие элементов в коллекции и получить их.

All

Метод All() проверяет, соответствуют ли все элементы условию. Если все элементы соответствуют условию, то возвращается true. Например:

string[] people = { "Tom", "Tim", "Bob", "Sam" };

// проверяем, все ли элементы имеют длину в 3 символа
bool allHas3Chars = people.All(s => s.Length == 3);     // true
Console.WriteLine(allHas3Chars);

// проверяем, все ли строки начинаются на T
bool allStartsWithT = people.All(s => s.StartsWith("T"));   // false
Console.WriteLine(allStartsWithT);

В первом случае проверяем, все ли строки в массиве people имеют длину в три символа. Поскольку это условие верно, то метод All возвращает true. Во втором случае смотрим, все ли строки начинаются с буквы "T". это условие ложно, поэтому метод All возвращает false.

Any

Метод Any() действует подобным образом, только возвращает true, если хотя бы один элемент коллекции определенному условию:

string[] people = { "Tom", "Tim", "Bob", "Sam" };

// проверяем, все ли элементы имеют длину больше 3 символов
bool allHasMore3Chars = people.Any(s => s.Length > 3);     // false
Console.WriteLine(allHasMore3Chars);

// проверяем, все ли строки начинаются на T
bool allStartsWithT = people.Any(s => s.StartsWith("T"));   // true
Console.WriteLine(allStartsWithT);

Первое выражение вернет false, поскольку все строки имеют длину в 3 символа. Второе выражение возвратит true, так как у нас есть в коллекции есть строки, которые начинаются на букву T.

Contains

Метод Contains() возвращает true, если коллекция содержит определенный элемент.

string[] people = { "Tom", "Tim", "Bob", "Sam" };

// проверяем, есть ли строка Tom
bool hasTom = people.Contains("Tom");     // true
Console.WriteLine(hasTom);

// проверяем, есть ли строка Mike
bool hasMike = people.Contains("Mike");     // false
Console.WriteLine(hasMike);

Стоит отметить, что для сравнения объектов применяется реализация метода Equals. Соответственно если мы работаем с объектами своих типов, то мы можем реализовать данный метод:

Person[] people = { new Person("Tom"), new Person("Sam"), new Person("Bob")};

var tom = new Person("Tom");
var mike = new Person("Mike");

// проверяем, есть ли Tom
bool hasTom = people.Contains(tom);     // true
Console.WriteLine(hasTom);

// проверяем, есть ли строка Mike
bool hasMike = people.Contains(mike);     // false
Console.WriteLine(hasMike);

class Person
{
    public string Name { get;}
    public Person(string name) => Name = name;

    public override bool Equals(object? obj)
    {
        if (obj is Person person) return Name == person.Name;
        return false;
    }
    public override int GetHashCode() => Name.GetHashCode();
}

Но стоит отметить, что Contains не всегда может вернуть ожидаемые данные. Например:

string[] people = { "tom", "Tim", "bOb", "Sam" };

// проверяем, есть ли строка Tom
bool hasTom = people.Contains("Tom");     // false
Console.WriteLine(hasTom);

// проверяем, есть ли строка Bob
bool hasMike = people.Contains("Bob");     // false
Console.WriteLine(hasMike);

В данном случае в массиве нет строки "Tom", а есть строка "tom". Поэтому вызов people.Contains("Tom") возвратит false. Но подобное поведение не всегда может быть желательным. И в этом случае мы можем задать логику сравнения с помощью реализации интерфейса IComparer и затем передать ее в качестве второго параметра в метод Contains:

using System.Diagnostics.CodeAnalysis;

string[] people = { "tom", "Tim", "bOb", "Sam" };

// проверяем, есть ли строка Tom
bool hasTom = people.Contains("Tom", new CustomStringComparer());     // true
Console.WriteLine(hasTom);

// проверяем, есть ли строка Bob
bool hasMike = people.Contains("Bob", new CustomStringComparer());     // true
Console.WriteLine(hasMike);

class CustomStringComparer : IEqualityComparer<string>
{
    public bool Equals(string? x, string? y)
    {
        if (x is null || y is null) return false;
        return x.ToLower() == y.ToLower();

    }

    public int GetHashCode(string obj) => obj.ToLower().GetHashCode();
}

Интерфейс IEqualityComparer типизируется типом сравниваемых данных (в данном случае типом String). Для реализации этого интерфейса необходимо определить методы Equals и GetHashCode. В методе Equals сравниваем строки в нижнем регистре, а в методе GetHashCode возвращаем возвращаем хеш-код строки в нижнем регистре.

First/FirstOrdefault

Метод First() возвращает первый элемент последовательности:

string[] people = { "Tom", "Bob", "Tim", "Sam" };

// проверяем, есть ли строка Tom
var first = people.First();  // Tom
Console.WriteLine(first);

Также в метод First можно передать метод, который представляет условие. В этом случае метод возвращает первый элемент, который соответствует условию:

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

// первая строка, длина которой равна 4 символам
var firstWith4Chars = people.First(s=> s.Length == 4);  // Kate
Console.WriteLine(firstWith4Chars);

Здесь выбираем первый элемент, длина которого - 4 символа.

Стоит учитывать, что если коллекция пуста или в коллекции нет элементов, который соответствуют условию, то будет сгенерировано исключение.

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

// первая строка, длина которой равна 5 символам
var firstWith5Chars = people.First(s => s.Length == 5);  // ! исключение
Console.WriteLine(firstWith5Chars);

var first = new string[] {}.First();  // ! исключение
Console.WriteLine(first);

FirstOrdefault

Метод FirstOrDefault() также возвращает первый элемент и также может принимать условие, только если коллекция пуста или в коллекции не окажется элементов, которые соответствуют условию, то метод возвращает значение по умолчанию:

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

// первый элемент
var first = people.FirstOrDefault();  // Tom
Console.WriteLine(first);

// первая строка, длина которой равна 4 символам
var firstWith4Chars = people.FirstOrDefault(s => s.Length == 4);  // Kate
Console.WriteLine(firstWith4Chars);

// первый элемент из пустой коллекции
var firstOrDefault = new string[] {}.FirstOrDefault();
Console.WriteLine(firstOrDefault);  // null

Стоит учитывать, что для коллекций ссылочных типов FirstOrDefault возвращает значение типа T? (в примере выше - string?), то есть значение, которое может быть равно null, а значение по умолчанию - null. Для коллекций числовых типов возвращается непосредственно значение типа T, а значение по умолчанию - 0.

Но мы можем настроить значение по умолчанию, передав его в качестве одного из аргументов:

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

string? firstWith5Chars = people.FirstOrDefault(s => s.Length == 5, "Undefined");
Console.WriteLine(firstWith5Chars); // Undefined

// первый элемент из пустой коллекции строк
string? firstOrDefault = new string[] {}.FirstOrDefault("hello"); // hello - значение по умолчанию
Console.WriteLine(firstOrDefault);  // hello

// первый элемент из пустой коллекции int
int firstNumber = new int[] {}.FirstOrDefault(100); // 100 - значение по умолчанию
Console.WriteLine(firstNumber); // 100

Last и LastOrDefault

Метод Last() аналогичен по работе методу First, только возвращает последний элемент. Если коллекция не содержит элемент, который соответствуют условию, или вообще пуста, то метод генерирует исключение.

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

string last = people.Last();
Console.WriteLine(last); // Sam

string lastWith4Chars = people.Last(s => s.Length == 4);
Console.WriteLine(lastWith4Chars); // Mike

Метод LastOrDefault() возвращает последний элемент или значение по умолчанию, если коллекция не содержит элемент, который соответствуют условию, или вообще пуста:

string[] people = { "Tom", "Bob", "Kate", "Tim", "Mike", "Sam" };

string? last = people.LastOrDefault();
Console.WriteLine(last); // Sam

string? lastWith4Chars = people.LastOrDefault(s => s.Length == 4);
Console.WriteLine(lastWith4Chars); // Mike

string? lastWith5Chars = people.LastOrDefault(s => s.Length == 5);
Console.WriteLine(lastWith5Chars); // null

string? lastWith5CharsOrDefault = people.LastOrDefault(s => s.Length == 5, "Undefined");
Console.WriteLine(lastWith5CharsOrDefault); // Undefined

// первый элемент из пустой коллекции строк
string? lastOrDefault = new string[] {}.LastOrDefault("hello");
Console.WriteLine(lastOrDefault);  // hello
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850