Задача отбора
Объект — массив целых чисел класса AROB. Требуется выбрать из этого массива элементы, удовлетворяющие некоторому, неизвестному пока, условию. И сохранить отобранные элементы в другой объект.
Объявим в классе AROB делегат
public delegate bool EQU(int x);
В классе AROB объявим метод, осуществляющий этот отбор:
public AROB Find_All(EQU equ)
Для отбора необходимых элементов массива из объекта X в объект Y достаточно вместо equ написать нужный предикат, например:
Y = X.Find_All(x => x > 25);
где лямбда-выражение в скобках метода указывает условие отбора.
Далее все должно быть понятно из комментариев в тексте.
Программная реализация
using System; namespace ARRAY_OBJECT { public class Program { public static void Main() { AROB X = new AROB(12, 1, 50); X.Out("Начальный массив"); AROB Y; Y = X.Find_All(x => x > 25); // в скобках - конкретизируем предикат от х через задание лямбда-функции: Y.Out("Выборка x > 25"); AROB Z; // или так: Z = X.Find_All(x => x < 26); Z.Out("Выборка x < 26"); } } public class AROB { // делегат public delegate bool EQU(int x); // поля класса AROB protected int n; protected int[] a; // конструктор 1 public AROB(int N) { n = N; a = new int[n]; } // конструктор 2 public AROB(int N, int min, int max) { Random rnd = new Random(); n = N; a = new int[n]; for (int i = 0; i < n; i++) a[i] = rnd.Next(min, max + 1); } // Метод - Вывод массива public void Out(string info) { Console.WriteLine(info); foreach (int el in a) Console.Write(el + "\t"); Console.WriteLine(); } // Метод Изменить j-й элемент массива на E public void Set_Element(int j, int E) { a[j] = E; } // Метод "Получить выборку - новый массив через экземпляр делегата equ // Вместо edu - любое лямбда-выражение - предикат от одной целочисленной переменной public AROB Find_All(EQU equ) { int b = 0; // число элементов, для которых equ(x) = true foreach(int el in a) if(equ(el)) b += 1; AROB Y = new AROB(b); // инициализация нового массива // заполнение нового массива по условию equ(x) = true b = 0; for (int i = 0; i < n; i++) if (equ(a[i])) { Y.Set_Element(b, a[i]); b++; } return Y; } } }
Встроенный делегат Action и лямбда оператора
Делегат задает формат методов void:
public delegate void Action(T obj);
Данный делегат имеет ряд перегруженных версий. Каждая версия принимает разное число параметров, может передано до 16 значений в метод.
Создадим стандартное приветствие: Привет, имя!
Решение
Action greet = name => { string greeting = $"Hello, {name}!"; Console.WriteLine(greeting); };
Вызов метода с передачей одного параметра string (может использоваться многократно, меняя имя):
greet("Alexander");
Получим: Hello, Alexander!
Встроенный делегат Predicate и лямбда выражения
используется для сопоставления некоторого объекта T определенному условию. В качестве выходного результата возвращается значение True, если условие соблюдено, и False, если нет.
Решение
Predicate isPositive = delegate (int x) { return x > 0; }; // где {...} - тело метода (на вход - int x, результат - bool по типу встроенного делегата) Predicate isNegative = y => y < 0; Console.WriteLine(isPositive(20)); // true Console.WriteLine(isNegative(-20)); // true
В отличие от Action делегат Predicate в качестве входного значения принимает один объект. Поэтому если на вход делегата хотите подать большее количество данных, объедините их в структуру или класс.
Делегат Predicate, структура и лямбда выражения
Пусть вне класса объявлена следующая структура:
public struct XYZ { public int x; public int y; public int z; public XYZ(int X, int Y, int Z) { x = X; y = Y; z = Z; } }
И пусть нам требуется проверка условия строгой упорядоченности чисел по убыванию. Тогда:
Решение
Predicate isPositiv = P => P.x > P.y; // лямбда-выражение Predicate isDownStrong = P => P.x > P.y && P.x > P.z && P.y > P.z; // XYZ p = new XYZ(7,6,6); Console.WriteLine(isPositiv(p)); // True Console.WriteLine(isDownStrong(p)); // False
Func — встроенный тип делегата и лямбда выражение
Делегат Func< >() является наиболее общим встроенным делегатом. Он возвращает результат действия и может принимать параметры. Он имеет различные формы:
от Func<out T>(), где T — тип возвращаемого значения,
до Func <in T1, in T2, … , in T16, out TResult >(),
то есть может принимать до 16 параметров
Пример. Т1 = int, Tresult = bool.
Func<int, bool> equalsFive = x => x == 5; // лямбда-выражение bool result = equalsFive(4); Console.WriteLine(result); // False result = equalsFive(5); Console.WriteLine(result); // true
Пример 2. Т1 = int, T2 = int, Tresult = int.
Func<int, int, int> MultyXY = (x,y) => x * y; int res = MultyXY(4,5); Console.WriteLine(res); // 20 res = MultyXY(5,5); Console.WriteLine(res); // 25
Пример 2а. Или через собственный делегат, объявленный как
delegate int DelegateType(int i, int j);
который равнозначен Func<int, int, int>
DelegateType myDelegate = (x,y) => x * y; int square = myDelegate(5,6); // 30 Console.WriteLine(square);
Пример 3. Подстановка лямбды выражения вместо имени метода
Пусть имеется некоторый метод, который выполняет вычисления только, если x1 > 0 (иначе результат = 0).
static double GetDouble(double x1, Func<double, double> retF) { double result = 0; if (x1 > 0) result = retF(x1); return result; }
Тогда вызов метода, вычисляющего произвольное лямбда выражение, запишется просто:
double n2 = GetDouble(6, x => x * x); Console.WriteLine(n2);
Результат: 36
ПРИМЕРЫ из LINQ
Пример 1. Используя лямбду выражения, подсчитать количество четных или нечетных чисел.
Пусть задан некоторый массив целых чисел. Тогда можно использовать метод Count(), в котором условие отбора задается лямбда выражением:
int[] numbers = { 1, 2, 3, 4, 5, 55, 7, 8, 9, 10 }; int pairs = numbers.Count(n => n % 2 == 0); Console.WriteLine(pairs); // 4 pairs = numbers.Count(n => n % 2 == 1); Console.WriteLine(pairs); // 6
Пример 2. Метод Average().
При использовании Query-синтаксиса мы запишем (массив numbers из примера 1):
var average1 = (from num in numbers where num > 6 select num).Average(); // Console.WriteLine(average1); // 17,8
То же самое, используя лямбду выражения, запишется так:
double average2 = numbers.Where(num => num < 5).Average(); Console.WriteLine(average); // 2,5
Пример 3 Использование метода Sum():
int summ = numbers.Where(num => num < 5).Sum(); Console.WriteLine(summ); // 10
Проверьте эту же конструкцию для методов Max, Min, LongCount.
NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.