Объяснение методов LINQ в .NET с помощью изображений
![Объяснение методов LINQ в .NET с помощью изображений](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/e4c77aee-8214-418b-a420-2a9284aa9212.png)
Довольно часто разработчики, начиная работать с LINQ методами, не до конца понимают принцип их работы, в этой статье объясняем как работают основные LINQ методы с помощью иллюстраций
Select
![select linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/b09199c1-2dd3-4cda-8f66-c1d22f84f87e.png)
С помощью select мы создаем проекцию одного элемента на другой. Проще говоря, мы сопоставляем наш заданный тип с желаемым типом. Результирующий набор содержит то же количество элементов, что и исходный набор данных.
Пример использования Select:
var people = new List<Person>
{
new Person ("Tom", 23),
new Person ("Bob", 27),
new Person ("Sam", 29),
new Person ("Alice", 24)
};
var names = people.Select(u => u.Name);
foreach (string n in names)
Console.WriteLine(n);
Where
![where linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/be0ddcba-0195-42cd-8bbd-dc28a0c4f385.png)
Where фильтрует набор значений базируясь на Func<TSource,bool>
предикате. В данном примере мы хотим получить только зеленые круги. Набор результатов может быть таким же, меньшим или даже пустым.
Пример использования Where
List<string> fruits =
new List<string> { "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
/*
This code produces the following output:
apple
mango
grape
*/
SelectMany
![selectmany linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/f2c003de-304e-4ba2-a3fe-379e4702e2fa.png)
SelectMany используется для выравнивания списков. Если у вас есть список внутри списка, мы можем использовать его, чтобы свести его к одномерному представлению.
Пример использования SelectMany
class PetOwner
{
public string Name { get; set; }
public List<string> Pets { get; set; }
}
public static void SelectManyEx2()
{
PetOwner[] petOwners =
{ new PetOwner { Name="Higa, Sidney",
Pets = new List<string>{ "Scruffy", "Sam" } },
new PetOwner { Name="Ashkenazi, Ronen",
Pets = new List<string>{ "Walker", "Sugar" } },
new PetOwner { Name="Price, Vernette",
Pets = new List<string>{ "Scratches", "Diesel" } },
new PetOwner { Name="Hines, Patrick",
Pets = new List<string>{ "Dusty" } } };
// Project the items in the array by appending the index
// of each PetOwner to each pet's name in that petOwner's
// array of pets.
IEnumerable<string> query =
petOwners.SelectMany((petOwner, index) =>
petOwner.Pets.Select(pet => index + pet));
foreach (string pet in query)
{
Console.WriteLine(pet);
}
}
// This code produces the following output:
//
// 0Scruffy
// 0Sam
// 1Walker
// 1Sugar
// 2Scratches
// 2Diesel
// 3Dusty
Zip
![Zip linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/b3fcd830-a51b-4285-af0c-b47146a56c1b.png)
С помощью Zip мы «объединяем» два списка с помощью заданной функции слияния. Мы объединяем объекты вместе, пока не закончатся объекты в любом из списков. Как видно из примера: в первом списке 2 элемента, в втором — 3. Следовательно, результирующий набор содержит только 2 элемента.
Пример использования Zip
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
Console.WriteLine(item);
// This code produces the following output:
// 1 one
// 2 two
// 3 three
OrderBy
![order by linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/572db8a4-4209-4972-b3ff-f38887963581.png)
OrderBy сортирует элементы последовательности в порядке возрастания. Результирующий набор содержит то же количество элементов, что и исходный набор.
Пример использования OrderBy
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void OrderByEx1()
{
Pet[] pets = { new Pet { Name="Barley", Age=8 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=1 } };
IEnumerable<Pet> query = pets.OrderBy(pet => pet.Age);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
}
/*
This code produces the following output:
Whiskers - 1
Boots - 4
Barley - 8
*/
Distinct
![distinct linq explanation](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/c24a1d37-3f2a-4f72-a414-d3fd064a51a0.png)
Distinct возвращает новый enumerable, в котором удаляются все дубликаты, что-то похожее на Set. Обратите внимание, что для ссылочного типа по умолчанию проверяется равенство ссылок, что может привести к ложным результатам. Результирующий набор может быть таким же или меньшим.
Пример использования Distinct
List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
IEnumerable<int> distinctAges = ages.Distinct();
Console.WriteLine("Distinct ages:");
foreach (int age in distinctAges)
{
Console.WriteLine(age);
}
/*
This code produces the following output:
Distinct ages:
21
46
55
17
*/
DistinctBy
![DistinctBy linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/f08dd896-a743-4be2-97fb-6d457f4b7875.png)
DistinctBy работает аналогично Distinct, но вместо уровня самого объекта мы можем определить проекцию на свойство, где мы хотим получить отдельный набор результатов.
Пример использования DistinctBy
public record Agent
{
public string Name { get; init; }
public byte Age { get; init; }
}
var agents = new[]
{
new Agent() {Name = "Ethan Hunt", Age = 40},
new Agent() {Name = "James Bond", Age = 40},
new Agent() {Name = "Jason Bourne", Age = 35},
new Agent() {Name = "Evelyn Salt", Age = 30},
new Agent() {Name = "Jack Ryan", Age = 36},
new Agent() {Name = "Jane Smith", Age = 35},
new Agent() {Name = "Oren Ishii", Age = 30},
new Agent() {Name = "Natasha Romanoff", Age = 33}
};
var distinctlyAgedAgents = agents.DistinctBy(x => x.Age);
foreach (var agent in distinctlyAgedAgents)
{
Console.WriteLine($"Agent {agent.Name} is {agent.Age}");
}
Agent Ethan Hunt is 40
Agent Jason Bourne is 35
Agent Evelyn Salt is 30
Agent Jack Ryan is 36
Agent Natasha Romanoff is 33
Aggregate
![Aggregate linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/aeb485d4-1ca6-407e-8b4a-4b3dd923b1d7.png)
Также известен как «reduce». Основная идея состоит в том, чтобы объединить/свести набор входных данных к одному значению. Сумма списка будет примером агрегата. Также яркими примерами могут быть определение среднего / максимального / минимального значения. Он всегда начинается с начального значения, и каждый отдельный элемент в списке агрегируется заданной пользователем функцией сверху.
Пример использования Aggregate
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
// Determine whether any string in the array is longer than "banana".
string longestName =
fruits.Aggregate("banana",
(longest, next) =>
next.Length > longest.Length ? next : longest,
// Return the final result as an upper case string.
fruit => fruit.ToUpper());
Console.WriteLine(
"The fruit with the longest name is {0}.",
longestName);
// This code produces the following output:
//
// The fruit with the longest name is PASSIONFRUIT.
Chunk
![Chunk linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/bfb9a627-ce84-4dfb-8114-c3e868db4dcd.png)
Работает начиная с .NET 6. Разбивает 1 список на несколько списков с заданым размером.
Пример использования Chunk
// Giving an enumerable
var e = Enumerable.Range(1, 999);
// Here it is. Enjoy :)
var chunks = e.Chunk(29);
// Sample, iterating over chunks
foreach(var chunk in chunks) // for each chunk
{
foreach(var item in chunk) // for each item in a chunk
{
Console.WriteLine(item);
}
}
Share
Edit
Union
![Union linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/0e92064f-0a3c-4757-8b30-5156672fc8d3.png)
Самое простое объяснение того как это работает: представьте, что у вы смержили 2 списка в один, и вызвали Distinct.
Пример использования Union
int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };
IEnumerable<int> union = ints1.Union(ints2);
foreach (int num in union)
{
Console.Write("{0} ", num);
}
/*
This code produces the following output:
5 3 9 7 8 6 4 1 0
*/
Intersect
![Intersect linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/6762dd9f-60b8-49c6-9eaa-8902aa131ba3.png)
Работает аналогично Union, но теперь мы проверяем, какие элементы присутствуют в списке A и списке B. В результирующем наборе будут только элементы, присутствующие в обоих списках. Также здесь: в новом списке только уникальные айтемы. Дубликаты удаляются автоматически.
Пример использования Intersect
int[] id1 = { 44, 26, 92, 30, 71, 38 };
int[] id2 = { 39, 59, 83, 47, 26, 4, 30 };
IEnumerable<int> both = id1.Intersect(id2);
foreach (int id in both)
Console.WriteLine(id);
/*
This code produces the following output:
26
30
*/
Any
![any linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/c16cd475-4391-4168-86f9-218d9916497d.png)
Any проверяет, удовлетворяет ли хотя бы один элемент вашему условию. Если это так, он возвращает true. Если нет элемента, удовлетворяющего условию, возвращается false.
Пример использования Any
List<int> numbers = new List<int> { 1, 2 };
bool hasElements = numbers.Any();
Console.WriteLine("The list {0} empty.",
hasElements ? "is not" : "is");
// This code produces the following output:
//
// The list is not empty.
All
![all linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/40127093-a225-4616-b08e-0cadc9d40821.png)
Как следует из названия, проверяет, удовлетворяют ли ВСЕ ваши элементы в списке определенному условию. Если да, то возвращает true, иначе false.
Пример использования All
class Pet
{
public string Name { get; set; }
public int Age { get; set; }
}
public static void AllEx()
{
// Create an array of Pets.
Pet[] pets = { new Pet { Name="Barley", Age=10 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=6 } };
// Determine whether all pet names
// in the array start with 'B'.
bool allStartWithB = pets.All(pet =>
pet.Name.StartsWith("B"));
Console.WriteLine(
"{0} pet names start with 'B'.",
allStartWithB ? "All" : "Not all");
}
// This code produces the following output:
//
// Not all pet names start with 'B'.
Append
![Append linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/642e6cc1-0d16-4874-924a-f3154e82a7d0.png)
Append помещает данный элемент в конец списка.
Пример использования Append
List<int> numbers = new List<int> { 1, 2, 3, 4 };
List<int> newNumbers = numbers.Append(5).ToList();
// 1, 2, 3, 4, 5
Prepend
![Prepend linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/baf9aae3-6a5c-4213-b04a-61379d4fc37a.png)
Помещает заданный элемент в начало списка.
Пример использования Prepend
List<int> numbers = new List<int> { 1, 2, 3, 4 };
List<int> newNumbers = numbers.Prepend(0).ToList();
// 0, 1, 2, 3, 4
MaxBy
![MaxBy linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/db8d5d38-2fd3-4d57-a883-9df6c24bd646.png)
С помощью MaxBy, а также MinBy мы также можем сделать проекцию на свойство нашего класса и получить объект, где именно это свойство является «самым большим».
Пример использования MaxBy
List<Person> people = new List<Person>
{
new Person
{
Name = "John Smith",
Age = 20
},
new Person
{
Name = "Jane Smith",
Age = 30
}
};
Console.Write(people.MaxBy(x => x.Age)); //Outputs Person (Jane Smith)
ToLookup
![ToLookup linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/e6846dbf-4827-48ab-be0d-e7412641a4f1.png)
Создает универсальный объект Lookup<TKey,TElement>
из объекта IEnumerable<T>
. Lookup
определяется тем, что у нас есть ключ, который может указывать на список объектов (отношение 1 к n). Первый аргумент принимает "key"-селектор. Второй селектор — это «значение». Это может быть сам объект или свойство самого объекта. В конце у нас есть список различных ключей, в которых значения имеют именно этот ключ. Объект LookUp неизменяем.
Пример использования ToLookup
class Package
{
public string Company { get; set; }
public double Weight { get; set; }
public long TrackingNumber { get; set; }
}
public static void ToLookupEx1()
{
// Create a list of Packages.
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard",
Weight = 25.2, TrackingNumber = 89453312L },
new Package { Company = "Lucerne Publishing",
Weight = 18.7, TrackingNumber = 89112755L },
new Package { Company = "Wingtip Toys",
Weight = 6.0, TrackingNumber = 299456122L },
new Package { Company = "Contoso Pharmaceuticals",
Weight = 9.3, TrackingNumber = 670053128L },
new Package { Company = "Wide World Importers",
Weight = 33.8, TrackingNumber = 4665518773L } };
// Create a Lookup to organize the packages.
// Use the first character of Company as the key value.
// Select Company appended to TrackingNumber
// as the element values of the Lookup.
ILookup<char, string> lookup =
packages
.ToLookup(p => p.Company[0],
p => p.Company + " " + p.TrackingNumber);
// Iterate through each IGrouping in the Lookup.
foreach (IGrouping<char, string> packageGroup in lookup)
{
// Print the key value of the IGrouping.
Console.WriteLine(packageGroup.Key);
// Iterate through each value in the
// IGrouping and print its value.
foreach (string str in packageGroup)
Console.WriteLine(" {0}", str);
}
}
/*
This code produces the following output:
C
Coho Vineyard 89453312
Contoso Pharmaceuticals 670053128
L
Lucerne Publishing 89112755
W
Wingtip Toys 299456122
Wide World Importers 4665518773
*/
ToDictionary
![ToDictionary linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/eaff20b1-cf20-438c-a68c-d6021886e396.png)
ToDictionary работает аналогично ToLookup с одним ключевым отличием. Метод ToDictionary допускает только отношения 1 к 1. Если два элемента используют один и тот же ключ, это приведет к исключению, что ключ уже присутствует.
Пример использования ToDictionary
class Package
{
public string Company { get; set; }
public double Weight { get; set; }
public long TrackingNumber { get; set; }
}
public static void ToDictionaryEx1()
{
List<Package> packages =
new List<Package>
{ new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },
new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },
new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },
new Package { Company = "Adventure Works", Weight = 33.8, TrackingNumber = 4665518773L } };
// Create a Dictionary of Package objects,
// using TrackingNumber as the key.
Dictionary<long, Package> dictionary =
packages.ToDictionary(p => p.TrackingNumber);
foreach (KeyValuePair<long, Package> kvp in dictionary)
{
Console.WriteLine(
"Key {0}: {1}, {2} pounds",
kvp.Key,
kvp.Value.Company,
kvp.Value.Weight);
}
}
/*
This code produces the following output:
Key 89453312: Coho Vineyard, 25.2 pounds
Key 89112755: Lucerne Publishing, 18.7 pounds
Key 299456122: Wingtip Toys, 6 pounds
Key 4665518773: Adventure Works, 33.8 pounds
*/
Join
![Join linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/07ef9edd-c37d-4c25-bae6-7283aa3119f9.png)
Join работает аналогично к SQL left-join.
Пример использования Join
class Person
{
public string Name { get; set; }
}
class Pet
{
public string Name { get; set; }
public Person Owner { get; set; }
}
public static void JoinEx1()
{
Person magnus = new Person { Name = "Hedlund, Magnus" };
Person terry = new Person { Name = "Adams, Terry" };
Person charlotte = new Person { Name = "Weiss, Charlotte" };
Pet barley = new Pet { Name = "Barley", Owner = terry };
Pet boots = new Pet { Name = "Boots", Owner = terry };
Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
List<Person> people = new List<Person> { magnus, terry, charlotte };
List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
// Create a list of Person-Pet pairs where
// each element is an anonymous type that contains a
// Pet's name and the name of the Person that owns the Pet.
var query =
people.Join(pets,
person => person,
pet => pet.Owner,
(person, pet) =>
new { OwnerName = person.Name, Pet = pet.Name });
foreach (var obj in query)
{
Console.WriteLine(
"{0} - {1}",
obj.OwnerName,
obj.Pet);
}
}
/*
This code produces the following output:
Hedlund, Magnus - Daisy
Adams, Terry - Barley
Adams, Terry - Boots
Weiss, Charlotte - Whiskers
*/
Take
![Take linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/0acfa59c-d10e-4ee2-bd67-0a26250cb113.png)
Take позволяет нам получить заданное количество элементов из массива. Если у нас меньше элементов в массиве, чем мы хотим получить, то Take() вернет только оставшиеся объекты.
Пример использования Take
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> topThreeGrades =
grades.OrderByDescending(grade => grade).Take(3);
Console.WriteLine("The top three grades are:");
foreach (int grade in topThreeGrades)
{
Console.WriteLine(grade);
}
/*
This code produces the following output:
The top three grades are:
98
92
85
*/
Skip
![Skip linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/447a93c3-e64e-4270-81df-42a1109cba2d.png)
С помощью Skip мы «пропускаем» заданное количество элементов. Если мы пропустим больше элементов, чем содержится в нашем списке, мы получим обратно пустое перечисление. Сочетание Take and Skip может быть очень полезным для таких вещей, как пагинация.
Пример использования Skip
int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
IEnumerable<int> lowerGrades =
grades.OrderByDescending(g => g).Skip(3);
Console.WriteLine("All grades except the top three are:");
foreach (int grade in lowerGrades)
{
Console.WriteLine(grade);
}
/*
This code produces the following output:
All grades except the top three are:
82
70
59
56
*/
OfType
![OfType linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/48fb8170-1ecc-44ea-9e8b-8170913e3ee4.png)
OfType проверяет каждый элемент в перечислении на предмет того, относится ли он к заданному типу (унаследованные типы также считаются данным типом) и возвращает их в новом перечислении. Это особенно помогает, если у нас есть нетипизированные массивы (объекты) или нам нужен специальный подкласс данного перечисления.
Пример использования OfType
System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
fruits.Add("Mango");
fruits.Add("Orange");
fruits.Add("Apple");
fruits.Add(3.0);
fruits.Add("Banana");
// Apply OfType() to the ArrayList.
IEnumerable<string> query1 = fruits.OfType<string>();
Console.WriteLine("Elements of type 'string' are:");
foreach (string fruit in query1)
{
Console.WriteLine(fruit);
}
// The following query shows that the standard query operators such as
// Where() can be applied to the ArrayList type after calling OfType().
IEnumerable<string> query2 =
fruits.OfType<string>().Where(fruit => fruit.ToLower().Contains("n"));
Console.WriteLine("\nThe following strings contain 'n':");
foreach (string fruit in query2)
{
Console.WriteLine(fruit);
}
// This code produces the following output:
//
// Elements of type 'string' are:
// Mango
// Orange
// Apple
// Banana
//
// The following strings contain 'n':
// Mango
// Orange
// Banana
GroupBy
![GroupBy linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/977937ed-7f4f-421a-b0ff-3e9d7a5cc70a.png)
Группирует элементы последовательности в соответствии с заданной функцией селектора ключа и создает результирующее значение для каждой группы и ее ключа
Пример использования GroupBy
class Pet
{
public string Name { get; set; }
public double Age { get; set; }
}
public static void GroupByEx4()
{
// Create a list of pets.
List<Pet> petsList =
new List<Pet>{ new Pet { Name="Barley", Age=8.3 },
new Pet { Name="Boots", Age=4.9 },
new Pet { Name="Whiskers", Age=1.5 },
new Pet { Name="Daisy", Age=4.3 } };
// Group Pet.Age values by the Math.Floor of the age.
// Then project an anonymous type from each group
// that consists of the key, the count of the group's
// elements, and the minimum and maximum age in the group.
var query = petsList.GroupBy(
pet => Math.Floor(pet.Age),
pet => pet.Age,
(baseAge, ages) => new
{
Key = baseAge,
Count = ages.Count(),
Min = ages.Min(),
Max = ages.Max()
});
// Iterate over each anonymous type.
foreach (var result in query)
{
Console.WriteLine("\nAge group: " + result.Key);
Console.WriteLine("Number of pets in this age group: " + result.Count);
Console.WriteLine("Minimum age: " + result.Min);
Console.WriteLine("Maximum age: " + result.Max);
}
/* This code produces the following output:
Age group: 8
Number of pets in this age group: 1
Minimum age: 8.3
Maximum age: 8.3
Age group: 4
Number of pets in this age group: 2
Minimum age: 4.3
Maximum age: 4.9
Age group: 1
Number of pets in this age group: 1
Minimum age: 1.5
Maximum age: 1.5
*/
}
Reverse
![Reverse linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/9b74001e-953b-4c6c-8d1c-212a04421324.png)
Reverse переварачивает массив в обратном порядке
Пример использования Reverse
char[] apple = { 'a', 'p', 'p', 'l', 'e' };
char[] reversed = apple.Reverse().ToArray();
foreach (char chr in reversed)
{
Console.Write(chr + " ");
}
Console.WriteLine();
/*
This code produces the following output:
e l p p a
*/
First
![first linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/ef13d7a2-b206-4aca-96a3-4020ab15d16d.png)
Возвращает первый элемент который подпадает под выборку.
Пример использования First
int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
83, 23, 87, 435, 67, 12, 19 };
int first = numbers.First(number => number > 80);
Console.WriteLine(first);
/*
This code produces the following output:
92
*/
Single
![Single linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/781a3f1c-d921-48b9-9d1a-4aef3c5ecab3.png)
Single не возвращается сразу после первого вхождения. Отличие от first в том, что Single гарантирует отсутствие второго элемента данного типа/предиката. Поэтому Single должен пройти все перечисление (в худшем случае), если он может найти другой элемент. Если существует более 1 записи, так же если элемент не найден он выдает исключение
Пример использования Single
string[] fruits1 = { "orange" };
string fruit1 = fruits1.Single();
Console.WriteLine(fruit1);
/*
This code produces the following output:
orange
*/
FirstOrDefault и SingleOrDefault
![single or default linq](https://joprblob.azureedge.net/site/blog/22b4b589-fecd-40d9-a810-2bd491448e89/5318390b-998a-44d7-9205-8b7b2815a893.png)
Если в данном перечислении не найден ни один элемент, он возвращает его по умолчанию (для ссылочных типов null и для типов значений заданное значение по умолчанию). Начиная с .NET6 мы можем передать то, что для нас означает «по умолчанию». Следовательно, мы можем иметь ненулевые ссылочные типы, если захотим.
Пример использования FirstOrDefault и SingleOrDefault
int[] numbers = { };
int first = numbers.FirstOrDefault(); // или SingleOrDefault
Console.WriteLine(first);
/*
This code produces the following output:
0
*/