Долгое время я откладывал изучение LINQ, полагая, что это довольно трудно. На деле же основы оказались очень простыми, при этом польза довольно ощутима. Изучив эту статью, вы сможете буквально в пару строк сможете делать выборки из списков, сортировать их, удалять дубли и т.д. Всё это мы и рассмотрим в этой статье.
Я не умею рассказывать "по-научному", так что давайте сразу посмотрим пример простого выражения и разберем его
Первое, что у нас тут есть, это список с фруктами (fruits). Вы можете использовать и зенковские списки, покажу чуть ниже, чтобы пока не путаться.
Результат будет положен в другой список с именем result.
Для выборки элементов из списка fruits мы используем метод Where, где в качестве параметра идет делегат. Но мы его как бы "составляем на ходу" и просто передаем лямбда выражение. Where у нас проверяет какое-то условие, и если оно истинно (возвращает true), то кладет элемент в новый список. Если нет (false), то пропускает этот элемент.
В "x" у нас кладется текущий элемент списка. Т.е. сначала там окажется "mango", на следующем круге "banana", затем "apple". Это как в цикле foreach, если вы с ним знакомы.
Каждый круг мы проверяем условие, которое идет после лямбды =>. В данном случае это выражение x.Contains("п"). Оно означает "содержит ли 'x' букву 'n'". Если да, то выражение вернет true, и мы положим текущий элемент в result. mango содержит n? Да, значит кладем в result. banana содержит n? Тоже кладем. apple содержит? Нет, значит его не берем.
ToList() преобразует IEnumerable (который возвращается по умолчанию) в List (т.е. в список). Лучше всегда преобразовывать либо в список, либо в массив (ToArray), т.к. с IEnumerable действует отложенное выполнение, на котором я не буду заостряться.
В результате у нас получается новый список с двумя элементами, удовлетворяющие заданному нами условию (x.Contains("n")).
В конце с помощью foreach выводим всё в лог.
==
Помимо Contains вы можете использовать абсолютно любое выражение, возвращающее true или false. Приведу несколько примеров.
Вы можете создавать и более сложные условия. Для этого используем фигурные скобки и пишем там, что душе угодно. Главное в конце вернуть булевое значение (для метода Where, для других возвращаем то, что ему нужно)
Всё то же самое можно делать и для зенковских списков, привязанных к файлам. Для обращения к зенковскому списку мы пишем project.List["название списка"]. Создайте список с именем "Список 1", привяжите к файлу, а в него забейте строки
mango
banana
apple
и запустите код
Т.к. почти все методы LINQ возвращают IEnumerable, мы можем запускать их по цепочке, выполняя сразу несколько операций над списком. В примере ниже мы сначала отберем слова, в которых содержится буква "n", затем переведем их в верхний регистр (с помощью метода Select), а затем отсортируем (с помощью метода OrderBy)
Помимо списков можно использовать массивы и другие коллекции, но некоторые из этих коллекций не имеют доступа к методам LINQ, но у них есть метод Cast. Если он есть, то используя этот метод можно будет пользоваться методами LINQ. Какие именно это коллекции - я не знаю (наверное, которые не реализуют интерфейс IEnumerable). Одна из таких - это MatcCollection (для работы с регулярками)
Мы можем использовать подзапросы. Пример сортировки по фамилии
Ну и ещё упомяну, что в LINQ есть иной синтаксис, который считается более удобным. Я с этим не согласен плюс там есть свои нюансы, так что я вам его покажу, но рассматривать не буду. В этом случае мы начинаем с from и заканчиваем либо select, либо group.
А теперь давайте рассмотрим некоторые из методов LINQ.
[1 перегрузка]Aggregate<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TSource,TSource> func) – функция в Aggregate принимает два параметра, где первый это текущий результат, а второй текущий элемент. Например, в примере ниже сначала в "x" кладётся apple, а в "y" passionfruit. Получается, что у нас вернулось "apple. passionfruit". В следующей итерации в "x" как раз и будет эта строка ("apple. passionfruit"), а в "y" кладётся следующий элемент, т.е. banana. У нас получается "apple. passionfruit. banana" и на следующем этапе уже это будет в "x", ну а в "y", соответственно, mango. Ну и т.д.
Другой пример
[2 перегрузка] public static TResult Aggregate<TSource,TAccumulate,TResult> (this System.Collections.Generic.IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate,TSource,TAccumulate> func, Func<TAccumulate,TResult> resultSelector)
[3 перегрузка] public static TAccumulate Aggregate<TSource,TAccumulate> (this System.Collections.Generic.IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate,TSource,TAccumulate> func) – аналогична второй, только тут в конце не производится финальное действие с результатом
public static bool All<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – проверяет, соответствуют ли все элементы указанному условию. Вернет true, если все элементы проходят условие.
public static bool Any<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – проверяет, соответствует ли хотя бы один элемент коллекции указанному условию.
public static System.Collections.Generic.IEnumerable<TSource> Append<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource element) – добавляет элемент в конец и возвращает новую коллекцию
public static System.Collections.Generic.IEnumerable<TSource> Prepend<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource element) – аналогичен Append, но добавляет в начало
public static double Average<TSource>(…) – считает среднее значение. можно использовать для всех числовых типов + для других тоже, если указать как будем считать среднее значение
public static System.Collections.Generic.IEnumerable<TResult> Cast<TResult> (this System.Collections.IEnumerable source) – некоторым коллекциям недоступны методы LINQ (OrderBy, Select и т.д.). Каким именно - я до конца не разобрался. Но если у этих коллекций есть метод Cast, тогда, использовав его, мы сможем вызывать наши методы
public static System.Collections.Generic.IEnumerable<TSource> Concat<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second) – соединяет две коллекции
public static bool Contains<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource value) – содержится ли элемент в коллекции
[1 перегрузка] public static int Count<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – вернёт количество элементов,
[2 перегрузка] public static int Count<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – можно задать доп. условие.
public static long LongCount<TSource> (…) – аналогичен Count(), только возвращает не int, а long.
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TSource?> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – если коллекция пуста, то добавляется значение по умолчанию.
[2 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource defaultValue) – если коллекция пуста, то добавляется указанное нами значение
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> Distinct<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – удаляет дубли
[2 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> Distinct<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, System.Collections.Generic.IEqualityComparer<TSource>? comparer) - для удаления дублей у своих объектов
public static TSource ElementAt<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, int index) – получение отдельного элемента из коллекции
public static TSource? ElementAtOrDefault<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, int index) – аналогичен ElementAt(), только если будет обращение по индексу вне диапазона, тогда вместо ошибки получим значение по умолчанию.
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> Except<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second) – метод оставит только те значения, что уникальны для первой коллекции (т.е. их нет во второй). Также если в первой коллекции есть дубли, они будут убраны. Вторая перегрузка нужна для своих объектов.
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> Intersect<TSource>(…) – аналогичен Except, только ищет уже пересечения, т.е. те элементы, что встречаются в обоих коллекциях. Вторая перегрузка нужна для своих объектов.
[1 перегрузка] public static TSource First<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – возвращает первый элемент коллекции.
[2 перегрузка] public static TSource First<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – можно задать условие
public static TSource FirstOrDefault<TSource>(…) – аналогичен First, но если коллекция пустая, то вернёт значение по умолчанию.
public static TSource Last<TSource> (…)
public static TSource? LastOrDefault<TSource> (…) – аналогичен First() и FirstOrDefault(), только возвращает последнее совпадение.
public static … Max (...) – возвращает наибольший элемент в коллекции. Можно задать доп условие (но меняется поведение для string, см пример). Строки он смотрит по алфавиту, т.е. при исп-и Max вернётся то значение, которое "дальше" всего по алфавиту
public static … Min (...) – аналогичен Max(), только возвращает минимальное значение
public static System.Collections.Generic.IEnumerable<TResult> OfType<TResult> (this System.Collections.IEnumerable source) – отбирает элементы указанного типа
public static System.Linq.IOrderedEnumerable<TSource> OrderBy<TSource,TKey> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TKey> keySelector) (this System.Collections.Generic.IEnumerable<T> source) – сортировка коллекции
public static System.Linq.IOrderedEnumerable<TSource> OrderByDescending<TSource,TKey> (…) – аналогичен OrderBy, только в обратном порядке
public static System.Collections.Generic.IEnumerable<int> Range (int start, int count) – генерация чисел подряд от какого-то. например, от десяти/пятнадцать штук (будет от 10 до 25)
public static System.Collections.Generic.IEnumerable<TResult> Repeat<TResult> (TResult element, int count) – "размножить" элемент
public static System.Collections.Generic.IEnumerable<TSource> Reverse<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – "перевернуть" коллекцию
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TResult> Select<TSource,TResult> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TResult> selector) – работает с элементами коллекциями (можно видоизменять)
[2 перегрузка] public static System.Collections.Generic.IEnumerable<TResult> Select<TSource,TResult> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,TResult> selector) – то же самое, только появляется индекс у элементов (с нуля), которым можно пользоваться.
public static System.Collections.Generic.IEnumerable<TResult> SelectMany<TSource,TResult> (…) - метод SelectMany проецирует каждый элемент последовательности в коллекцию и объединяет результаты в одну последовательность. Он используется для работы с коллекциями коллекций, где требуется "развернуть" вложенные коллекции в одну последовательность. Есть перегрузка с индексом (как у Select) и ещё парочку (их я не рассматривал)
Вот демонстрация отличий Select и SelectMany
public static bool SequenceEqual<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second) – сравнивает две коллекции. Если у них одинаковые элементы в одной и той же последовательности, то вернёт true. 2-я перегрузка для своих объектов.
public static TSource Single<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) - возвращает единственный элемент последовательности, удовлетворяющий указанному условию, и выдает исключение, если существует более одного такого элемента или их не существует ни одного.
public static TSource? SingleOrDefault<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – аналогичен Single(), но если ничего не найдено, вернёт значение по умолчанию
public static System.Collections.Generic.IEnumerable<TSource> Skip<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, int count) – позволяет пропустить указанное количество элементов из коллекции и вернуть остальное
public static System.Collections.Generic.IEnumerable<TSource> SkipWhile<TSource> (…) – пока элементы удовлетворяют условию, они пропускаются. Как только условие становится ложным, происходит возврат всех оставшихся элементов. Во второй перегрузке появляется возможность использовать index, который с каждым элементом возрастает на один.
public static … Sum (…) – ищет сумму чисел. Доступен для всех числовых типов. Для своих объектов тоже можно, указав как именно считать сумму.
public static System.Collections.Generic.IEnumerable<TSource> Take<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, int count) – возвращает указанное количество элементов из коллекции
public static System.Collections.Generic.IEnumerable<TSource> TakeWhile<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,bool> predicate) - возвращает элементы до тех пор, пока они соответствуют условию
public static System.Linq.IOrderedEnumerable<TSource> ThenBy<TSource,TKey> (this System.Linq.IOrderedEnumerable<TSource> source, Func<TSource,TKey> keySelector) - Выполняет последующее упорядочивание элементов в последовательности в порядке возрастания. Вторая перегрузка для своих объектов.
В примере ниже мы сначала отсортировываем по длине слов с помощью OrderBy(). Но их порядок остаётся тот же, что и в коллекции. Чтобы отсортировать их по алфавиту, мы используем ThenBy(). Получается, что сначала по алфавиту отсортировываются слова по 5 символов, далее по 6 символов и т.д.
public static System.Linq.IOrderedEnumerable<TSource> ThenByDescending<TSource,TKey> (this System.Linq.IOrderedEnumerable<TSource> source, Func<TSource,TKey> keySelector) – аналогичен ThenBy, только сортировка будет в обратном порядке
public static TSource[] ToArray<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – конвертирует коллекцию в массив
public static System.Collections.Generic.Dictionary<TKey,TValue> ToDictionary<TKey,TValue>(…) - конвертирует коллекцию в словарь.
public static System.Collections.Generic.HashSet<TSource> ToHashSet<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – конвертирует коллекцию в HashSet.
public static System.Collections.Generic.List<TSource> ToList<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – конвертирует коллекцию в список
public static System.Collections.Generic.IEnumerable<TSource> Union<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second) – объединяет две коллекции, отбрасывая дубли.
public static System.Collections.Generic.IEnumerable<TSource> Where<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – фильтрует коллекцию. Вторая перегрузка позволяет использовать индекс
GroupBy(…) – позволяет группировать элементы по какому-то признаку.
public static System.Collections.Generic.IEnumerable<TResult> Join<TOuter,TInner,TKey,TResult>(…) – Join используется для объединения элементов двух последовательностей по определённому признаку. Это позволяет анализировать данные и находить взаимосвязи между ними. Вот как можно использовать join в LINQ: Выбрать элементы из первой последовательности. Найти соответствующие элементы во второй последовательности на основе общего признака. Объединить выбранные элементы в одну последовательность. Применить функцию к каждой паре элементов, чтобы получить результат. Использовать полученные результаты для дальнейшей обработки или отображения.
Надеюсь, статья оказалась для вас полезной. Чтобы закрепить на практике, вы можете поискать сниппеты на форуме. Вбиваете название какого-нибудь метода в поиск и смотрите. Это позволит вам лучше понять, как это всё можно применить и где это вам пригодится. В видео мы рассмотрим парочку таких сниппетов и вынесем их в общий код, чтобы можно было вызывать одним методом.
Введение
Я не умею рассказывать "по-научному", так что давайте сразу посмотрим пример простого выражения и разберем его
C#:
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
List<string> result = fruits.Where(x=>x.Contains("n")).ToList();
foreach(var s in result) project.SendInfoToLog(s.ToString()); //mango, banana
Результат будет положен в другой список с именем result.
Для выборки элементов из списка fruits мы используем метод Where, где в качестве параметра идет делегат. Но мы его как бы "составляем на ходу" и просто передаем лямбда выражение. Where у нас проверяет какое-то условие, и если оно истинно (возвращает true), то кладет элемент в новый список. Если нет (false), то пропускает этот элемент.
В "x" у нас кладется текущий элемент списка. Т.е. сначала там окажется "mango", на следующем круге "banana", затем "apple". Это как в цикле foreach, если вы с ним знакомы.
Каждый круг мы проверяем условие, которое идет после лямбды =>. В данном случае это выражение x.Contains("п"). Оно означает "содержит ли 'x' букву 'n'". Если да, то выражение вернет true, и мы положим текущий элемент в result. mango содержит n? Да, значит кладем в result. banana содержит n? Тоже кладем. apple содержит? Нет, значит его не берем.
ToList() преобразует IEnumerable (который возвращается по умолчанию) в List (т.е. в список). Лучше всегда преобразовывать либо в список, либо в массив (ToArray), т.к. с IEnumerable действует отложенное выполнение, на котором я не буду заостряться.
В результате у нас получается новый список с двумя элементами, удовлетворяющие заданному нами условию (x.Contains("n")).
В конце с помощью foreach выводим всё в лог.
==
Помимо Contains вы можете использовать абсолютно любое выражение, возвращающее true или false. Приведу несколько примеров.
C#:
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
List<string> result = fruits.Where(x=>x.StartsWith("m")).ToList(); //начинается ли на букву m
foreach(var s in result) project.SendInfoToLog(s.ToString()); //mango
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
List<string> result = fruits.Where(x=>x.Length == 5).ToList(); //длина слова равна 5
foreach(var s in result) project.SendInfoToLog(s.ToString()); //mango, apple
C#:
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
List<string> result = fruits.Where(x=>{
if(x.Length == 5 && x.StartsWith("m"))
{
return true; //возвращаем, если длина == 5 и начинается на букву ,
}
return false; //во всех остальных случаях не возвращаем
}).ToList();
foreach(var s in result) project.SendInfoToLog(s.ToString()); //mango
mango
banana
apple
и запустите код
C#:
List<string> fruits = project.Lists["Список 1"].ToList(); //копируем данные из зенно списка в обычный
List<string> result = fruits.Where(x=>{
if(x.Length == 5 && x.StartsWith("m"))
{
return true;
}
return false;
}).ToList();
//очищаем старые данные и кладем новые. lock для блокировки в многопотоке
lock(SyncObjects.ListSyncer)
{
project.Lists["Список 1"].Clear();
project.Lists["Список 1"].AddRange(result);
}
C#:
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
List<string> result = fruits.Where(x=>x.Contains("n"))
.Select(x=>x.ToUpper())
.OrderBy(x=>x)
.ToList();
foreach(var s in result) project.SendInfoToLog(s.ToString()); //BANANA, MANGO
C#:
string str = "вася пошёл гулять";
string regex = @"вася"; //регулярка
List<string> result = Regex.Matches(str,regex) //метод Matches возвращает MatchCollection
.Cast<Match>() //используя Cast получаем доступ к методам LINQ
.Select(x=>x.ToString()) //select используется для получения текущего значения и его видоизменения
.ToList(); //преобразуем в список
C#:
List<string> names = new List<string> { "Василий Пупкин", "Аркадий Соловьёв", "Генадий Петров"};
//используем подзапрос, сортируем по фамилии
var res = names.OrderBy(x=>x.Split().Last());
foreach(var s in res) project.SendInfoToLog(s);
C#:
List<string> fruits = new List<string>() {"mango", "banana", "apple"};
var result = from s in fruits
where s.Length == 5
select s;
foreach(var s in result) project.SendInfoToLog(s); //mango, apple
Методы LINQ
[1 перегрузка]Aggregate<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,TSource,TSource> func) – функция в Aggregate принимает два параметра, где первый это текущий результат, а второй текущий элемент. Например, в примере ниже сначала в "x" кладётся apple, а в "y" passionfruit. Получается, что у нас вернулось "apple. passionfruit". В следующей итерации в "x" как раз и будет эта строка ("apple. passionfruit"), а в "y" кладётся следующий элемент, т.е. banana. У нас получается "apple. passionfruit. banana" и на следующем этапе уже это будет в "x", ну а в "y", соответственно, mango. Ну и т.д.
C#:
List<string> fruits =
new List<string> { "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
string query = fruits.Aggregate((x,y)=> {
return x + ". " + y;
});
return query; //apple. passionfruit. banana. mango. orange. blueberry. grape. strawberry
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string result1 = fruits.Aggregate((next, longest) => next += $". {longest}"); //apple. mango. orange. passionfruit. grape
string result2 = fruits.Aggregate((next, longest) => next.Length > longest.Length ? next : longest); //passionfruit. мы получили самое длинное слово
List<int> numbers = new List<int>(){ 1, 2, 3, 4, 5 };
int sum = numbers.Aggregate((x, y)=> x + y); //15. получили сумму всех чисел
int sumRandom = numbers.Aggregate((x, y) => {
int summa=0;
if(y > 2)
{
summa = x+y;
}
return summa;
});
return sumRandom;//12. тут я показал как можно использовать более сложную логику. просто открываем {} и пишем что душе угодно
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
//параметры: изначальное значение, с которым сравниваем, делегат, финальное действие с результатом (делегат)
string longestName =
fruits.Aggregate("banana",
(longest, next) =>
next.Length > longest.Length ? next : longest,
fruit => fruit.ToUpper()); //PASSIONFRUIT
string longestName2 =
fruits.Aggregate("banana2222222222222222222222222",
(longest, next) =>
next.Length > longest.Length ? next : longest,
fruit => fruit.ToUpper()); //BANANA2222222222222222222222222
return longestName2;
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
//параметры: изначальное значение, с которым сравниваем, делегат, финальное действие с результатом (делегат)
string longestName =
fruits.Aggregate("banana",
(longest, next) =>
next.Length > longest.Length ? next : longest
);
return longestName; //passionfruit
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
bool result = fruits.All(x=> x.Length > 4);
return result; //True, т.к. все элементы имеют длину больше 4 символов
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
bool result = fruits.Any(x=> x.Length > 10);
return result; //True, т.к. passionfruit больше 10 символов
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string[] fruitsAddFruit = fruits.Append("banana").ToArray();
foreach(var s in fruitsAddFruit) project.SendInfoToLog(s);
C#:
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
string[] fruitsAddFruit = fruits.Prepend("banana").ToArray();
return fruitsAddFruit[0]; //banana
C#:
List<int> numbers = new List<int>
{
1, 2, 3, 4, 5
};
double average = numbers.Average(); //3 т.к. это (1+2+3+4+5) / 5 == 3
project.SendInfoToLog(average.ToString());
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
average = fruits.Average(s => s.Length); //6.5 средняя длина фраз
project.SendInfoToLog(average.ToString());
C#:
MatchCollection kol = Regex.Matches(@"Васе Пупкину 12 лет, а Пете 9 лет", @"\d+");
List<Match> result = kol.Cast<Match>().OrderBy(x => Convert.ToInt32(x.Value)).ToList();
foreach(var s in result) project.SendInfoToLog(s.ToString()); //9, 12
System.Collections.ArrayList fruits = new System.Collections.ArrayList();
fruits.Add("mango");
fruits.Add("apple");
fruits.Add("lemon");
IEnumerable<string> query = fruits.Cast<string>().OrderBy(fruit => fruit).Select(fruit => fruit);
foreach(var s in query) project.SendInfoToLog(s.ToString()); //apple, lemon, mango
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
string[] array2 = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
IEnumerable<string> list = array.Concat(array2);
foreach(var s in list) project.SendInfoToLog(s);
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
bool result = array.Contains("Второй"); //True
[2 перегрузка] public static int Count<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – можно задать доп. условие.
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
int result = array.Count(); //5
int result2 = array.Count(x => x.Length > 6); //1. Возвращаем количество элементов, чья длина больше 6
return result2;
[1 перегрузка] public static System.Collections.Generic.IEnumerable<TSource?> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – если коллекция пуста, то добавляется значение по умолчанию.
[2 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> DefaultIfEmpty<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, TSource defaultValue) – если коллекция пуста, то добавляется указанное нами значение
C#:
string[] array = {};
List<string> resultList1 = array.DefaultIfEmpty("").ToList();
List<string> resultList2 = array.DefaultIfEmpty("gg").ToList();
string result1 = resultList1[0]; //""
string result2 = resultList2[0]; //gg
project.SendInfoToLog($"{result1}\n{result2}");
[2 перегрузка] public static System.Collections.Generic.IEnumerable<TSource> Distinct<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, System.Collections.Generic.IEqualityComparer<TSource>? comparer) - для удаления дублей у своих объектов
C#:
string[] array = {"Первый", "Второй", "Пятый", "Третий", "Третий", "Четвертый", "Пятый", "Пятый"};
string[] newArray = array.Distinct().ToArray();
foreach(var s in newArray) project.SendInfoToLog(s);
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
string el = array.ElementAt(1); //Второй
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
string el = array.ElementAtOrDefault(11); //null
C#:
double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.2 };
IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);
foreach (double number in onlyInFirstSet)
project.SendInfoToLog(number.ToString()); //2.0, 2.1, 2.3, 2.4, 2.5
C#:
double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.0, 2.0, 2.9, 2.1, 2.8 };
IEnumerable<double> result = numbers1.Intersect(numbers2);
foreach(var s in result) project.SendInfoToLog(s.ToString()); //2.0, 2.1
[2 перегрузка] public static TSource First<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,bool> predicate) – можно задать условие
C#:
double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double result = numbers1.First(); //2.0
double result2 = numbers1.First(x=> x > 2.3); //2.4
C#:
double[] numbers1 = {};
double result = numbers1.FirstOrDefault(); //0
double result2 = numbers1.FirstOrDefault(x=> x> 2); //0
public static TSource? LastOrDefault<TSource> (…) – аналогичен First() и FirstOrDefault(), только возвращает последнее совпадение.
C#:
double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
double result = numbers1.Last(); //2.5
double result2 = numbers1.Last(x=> x < 2.3); //2.2
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
string strResult = array.Max(); //Четвертый
int[] iArray = {55, 243, 1, 15};
int iResult = iArray.Max(); //243
int strResultPlus = array.Max(x=> x.Length + 5); //14. string он не возвращает вообще, поэтому считается длина слова + 5
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
string strResult = array.Min(); //Второй
int[] iArray = {55, 243, 1, 15};
int iResult = iArray.Min(); //1
int strResultPlus = array.Min(x=> x.Length); //5. т.к. я ему сказал брать длину слова, то он уже сравнивает по ней
C#:
System.Collections.ArrayList fruits = new System.Collections.ArrayList()
{
"Mango",
"Orange",
null,
"Apple",
3.0,
"Banana"
};
// Apply OfType() to the ArrayList.
IEnumerable<string> query1 = fruits.OfType<string>();
foreach (string fruit in query1)
{
project.SendInfoToLog(fruit); //Mango, Orange, Apple, Banana
}
C#:
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
string[] newFruits = fruits.OrderBy(x=>x).ToArray();
foreach(var s in newFruits) project.SendInfoToLog(s); //apple, banana, grape, ...
C#:
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
string[] newFruits = fruits.OrderByDescending(x=>x).ToArray();
foreach(var s in newFruits) project.SendInfoToLog(s); // passionfruit, orange, mango, ...
C#:
IEnumerable<int> squares = Enumerable.Range(5, 10); //параметры: откуда начинаем, сколько.
foreach (int num in squares)
{
project.SendInfoToLog(num.ToString()); //результат: 5,6,7,8,9,10,11,12,13,14
}
C#:
IEnumerable<string> strings =
Enumerable.Repeat("I like programming.", 4);
foreach (String str in strings)
{
project.SendInfoToLog(str); //I like programming. , I like programming. , I like programming. , I like programming.
}
C#:
string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
string[] revers = fruits.Reverse().ToArray();
foreach(var s in revers) project.SendInfoToLog(s); //grape, passionfruit, orange, ...
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
int i=1;
var list2 = array.Select(x => i++.ToString() + ". " + x);
foreach(var s in list2) project.SendInfoToLog(s);
/*
1. Первый
2. Второй
3. Третий
4. Четвертый
5. Пятый
*/
C#:
string[] array = {"Первый", "Второй", "Третий", "Четвертый", "Пятый"};
var list2 = array.Select((x, index) => index.ToString() + ". " + x);
foreach(var s in list2) project.SendInfoToLog(s);
/*
0. Первый
1. Второй
2. Третий
3. Четвертый
4. Пятый
*/
C#:
List<List<int>> numbers = new List<List<int>>
{
new List<int>
{
1, 2, 3
},
new List<int>
{
4, 5, 6
},
new List<int>
{
7, 8, 9
}
};
var allNumbers = numbers.SelectMany(list => list);
foreach (var number in allNumbers)
{
project.SendInfoToLog(number.ToString()); //1,2,3,4,5,6,7,8,9
}
C#:
List<string> sentences = new List<string>
{
"Hello World",
"LINQ is awesome",
"C# is great"
};
// Select
IEnumerable<string[]> words1 = sentences.Select(sentence => sentence.Split(' '));
project.SendInfoToLog(words1.ElementAt(0).ElementAt(0)); //Hello
project.SendInfoToLog(words1.ElementAt(0).ElementAt(1)); //World
project.SendInfoToLog(words1.ElementAt(1).ElementAt(0)); //LINQ
project.SendInfoToLog("============================");
// SelectMany
IEnumerable<string> words2 = sentences.SelectMany(sentence => sentence.Split(' '));
foreach (var word in words2)
{
project.SendInfoToLog(word);
}
C#:
string[] fruits1 = {"banana", "apple", "orange"};
string[] fruits2 = {"banana", "apple", "orange"};
string[] fruits3 = {"apple", "banana", "orange"};
bool result1 = fruits1.SequenceEqual(fruits2); //true
bool result2 = fruits1.SequenceEqual(fruits3); //false
project.SendInfoToLog($"result 1: {result1.ToString()}, result 2: {result2.ToString()}");
C#:
string[] fruits = {"banana", "apple", "orange"};
string result1 = fruits.Single(x=> x.Length == 5); //apple
try{
string result2 = fruits.Single(x=>x.Length == 6); //перебросит в catch
}
catch(Exception e){
project.SendInfoToLog("ошибка в методе Single, т.к. более одного элемента удовлетворяют условию. описание ошибки - " + e.Message);
}
C#:
string[] fruits = {"banana", "apple", "orange"};
string result1 = fruits.SingleOrDefault(x=> x.Length == 15); //null
C#:
string[] fruits = {"banana", "apple", "orange", "1", "2", "3"};
string[] result = fruits.Skip(3).ToArray(); //1,2,3
foreach(var s in result) project.SendInfoToLog(s);
C#:
string[] fruits = {"banana", "apple", "orange", "1", "2", "3", "end"};
string[] result = fruits.SkipWhile(x=> Regex.Match(x, @"[a-z]").Success).ToArray(); //"1", "2", "3", "end"
foreach(var s in result) project.SendInfoToLog(s);
int[] amounts = { 5000, 2500, 9000, 8000,
6500, 4000, 1500, 5500 };
IEnumerable<int> query =
amounts.SkipWhile((amount, index) => amount > index * 1000); //4000, 1500, 5500
C#:
string[] fruits = {"banana", "apple", "orange", "1", "2", "3", "end"};
int sum = fruits.Sum(x=> x.Length); // получаем сумму длин слов
return sum; //23.
C#:
string[] fruits = {"banana", "apple", "orange", "1", "2", "3", "end"};
var sum = fruits.Take(2);
foreach(var s in sum) project.SendInfoToLog(s); //banana, apple
C#:
string[] fruits = {"banana", "apple", "orange", "1", "2", "3", "ends"};
var sum = fruits.TakeWhile(x=> x.Length > 3);
foreach(var s in sum) project.SendInfoToLog(s); //banana, apple, orange
В примере ниже мы сначала отсортировываем по длине слов с помощью OrderBy(). Но их порядок остаётся тот же, что и в коллекции. Чтобы отсортировать их по алфавиту, мы используем ThenBy(). Получается, что сначала по алфавиту отсортировываются слова по 5 символов, далее по 6 символов и т.д.
C#:
string[] fruits = { "grape", "passionfruit", "banana", "mango",
"orange", "raspberry", "apple", "blueberry" };
var result = fruits.OrderBy(x=> x.Length); //grape, mango, apple, banana, orange, raspberry, blueberry, passionfruit
var result2 = result.ThenBy(x=>x); //apple, grape, mango, banana, orange, blueberry, raspberry, passionfruit
foreach(var s in result2) project.SendInfoToLog(s);
C#:
string[] fruits = { "grape", "passionfruit", "banana", "mango",
"orange", "raspberry", "apple", "blueberry" };
var result = fruits.OrderBy(x=> x.Length); //grape, mango, apple, banana, orange, raspberry, blueberry, passionfruit
var result2 = result.ThenByDescending(x=>x); //mango, grape, apple, orange, banana, raspberry, blueberry, passionfruit
foreach(var s in result2) project.SendInfoToLog(s);
public static System.Collections.Generic.Dictionary<TKey,TValue> ToDictionary<TKey,TValue>(…) - конвертирует коллекцию в словарь.
public static System.Collections.Generic.HashSet<TSource> ToHashSet<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – конвертирует коллекцию в HashSet.
public static System.Collections.Generic.List<TSource> ToList<TSource> (this System.Collections.Generic.IEnumerable<TSource> source) – конвертирует коллекцию в список
public static System.Collections.Generic.IEnumerable<TSource> Union<TSource> (this System.Collections.Generic.IEnumerable<TSource> first, System.Collections.Generic.IEnumerable<TSource> second) – объединяет две коллекции, отбрасывая дубли.
C#:
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)
{
project.SendInfoToLog(num.ToString());
}
C#:
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)
{
project.SendInfoToLog(fruit); //apple, mango, grape
}
C#:
List<string> fruits =
new List<string> { "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
IEnumerable<string> query = fruits.Where((fruit, index) => fruit.Length > 6 + index);
foreach (string fruit in query)
{
project.SendInfoToLog(fruit); //passionfruit
}
C#:
// Создаём список фруктов
var fruits = new List<string>
{
"баклажан", "яблоко", "апельсин", "ананас", "банан", "груша", "персик", "паприка", "баран"
};
// Группируем фрукты по первой букве
var groups = fruits.GroupBy(fruit => fruit[0]);
foreach (var group in groups)
{
foreach (var fruit in group )
project.SendInfoToLog($"{group.Key} : {fruit} ");
}
/*
б : баклажан
б : банан
б : баран
я : яблоко
а : апельсин
а : ананас
г : груша
п : персик
п : паприка */
C#:
// Создаём список фруктов
var fruits = new List<string>
{
"яблоко", "апельсин", "банан", "груша", "персик", "123456", "789012"
};
// Создаём список цветов
var colors = new List<string>
{
"красный", "оранжевый", "жёлтый", "зелёный", "голубой", "asdfgh"
};
// Соединяем фрукты и цвета по индексу
var joined = fruits.Join(colors, fruit => fruit.Length, color => color.Length, (fruit, color) => new
{
Fruit = fruit, Color = color
});
foreach (var item in joined)
project.SendInfoToLog($"{item.Fruit} - {item.Color}");
/*
яблоко - жёлтый
яблоко - asdfgh
персик - жёлтый
персик - asdfgh
123456 - жёлтый
123456 - asdfgh
789012 - жёлтый
789012 - asdfgh
*/
Заключение
Надеюсь, статья оказалась для вас полезной. Чтобы закрепить на практике, вы можете поискать сниппеты на форуме. Вбиваете название какого-нибудь метода в поиск и смотрите. Это позволит вам лучше понять, как это всё можно применить и где это вам пригодится. В видео мы рассмотрим парочку таких сниппетов и вынесем их в общий код, чтобы можно было вызывать одним методом.
Вложения
-
15,6 КБ Просмотры: 19
Последнее редактирование модератором: