130 likes | 382 Views
Лекция. Итераторы и LINQ. Интерфейс IEnumerable и IEnumerator. Любая коллекция реализует интерфейс IEnumerable. public interface IEnumerable < out T> : IEnumerable { IEnumerator <T> GetEnumerator (); }.
E N D
Лекция Итераторы и LINQ
Интерфейс IEnumerable и IEnumerator Любая коллекция реализует интерфейс IEnumerable. publicinterfaceIEnumerable<out T> : IEnumerable { IEnumerator<T> GetEnumerator(); } Объект, возвращаемый методом GetEnumerator(),называется итератор. Итератор реализует интерфейсIEnumerator<T>: publicinterfaceIEnumerator<out T> : IDisposable, IEnumerator { T Current { get; } boolMoveNext(); // false, когда дальше ехать некуда void Reset(); } Замечание. Интерфейс IEnumerator<T> не обязательно подразумевает коллекцию.
Ключевое слово yield Главным в интерфейсе IEnumerator<T> является метод MoveNext(), поэтому итератор можно объявить, запрограммировав только его, остальное компилятор доделает сам. Для этого в С# существует слово yield. IEnumerator<int> Iter() { yieldreturn 1; yieldreturn 2; yieldreturn 3; } for (variter = Iter(); iter.MoveNext(); ) Console.WriteLine(iter.Current); Если возвратить не IEnumerator<T> а IEnumerable<T>, то компилятор создаст боле удобный в использовании объект. • IEnumerable<int> Iter() { yieldreturn 1; yieldreturn 2; yieldreturn 3; } foreach (var i inIter()) Console.WriteLine(i);
Примеры итераторов Итератор может сам вырабатывать последовательность значений. staticIEnumerable<int> Range(int a, int b) { for (int i = a; i < b; i++) yieldreturni; } Итератор может основываться на входной последовательности. staticIEnumerable<int> Filter(IEnumerable<int> it) { foreach (var x in it) if (x % 2 == 0) yieldreturn x; }
Примеры итераторов Итератор может основываться на двух входных последовательностях. staticIEnumerable<Point> Decart(IEnumerable<int> a, IEnumerable<int> b) { foreach (var x in a) foreach (var y in b) yieldreturnnewPoint(x, y); } или на любом количестве входных последовательностей. staticIEnumerable<int> Maximes(paramsIEnumerable<int>[] xs) { foreach (var x in xs) yieldreturn Max(x); }
Что такое LINQ to Objects • Как показывают примеры, одни итераторы можно преобразовывать в другие итераторы, в числа, в массивы, вколлекцию, во что угодно. • Набор готовых методов-преобразователей, который содержится в статическом классе System.Linq.Enumerable, и составляет основное содержание LINQ to Objects.
Цепочечная композиция Большинство преобразователей имеют форму методов, расширяющих тип IEnumerable<T>, например, • publicstaticint Count<TSource>(thisIEnumerable<TSource> source); Композицию таких методов можно записать так. • int n = Enumerable.Range(1, 10).Where(x => x % 2 == 0).Count(); Для сравнения – композиция, записанная обычным способом. Enumerable.Count(Enumerable.Where(Enumerable.Range(1, 10), x => x % 2 == 0));
Выражения запросов От цепочечного выражения int n = Enumerable.Range(1, 10) .Where(x => x % 2 == 0) .Count(); один шаг до выражения запроса. var v = from x inEnumerable.Range(1, 10) where x % 2 == 0 select x; int n = v.Count();
Пример выражения запроса Выбрать из массива имен пятибуквенные имена и перевести их в верхний регистр. usingSystem; usingSystem.Linq; usingSystem.Collections.Generic; classProgram { staticvoid Main() { string[] names = { "Burke", "Connor", "Frank", "Everett", "Albert", "George", "Harris", "David"}; varquery = fromnameinnames wherename.Length == 5 orderbyname selectname.ToUpper(); foreach (string item in query) Console.WriteLine(item); } } BURKE DAVID FRANK
Компиляция запросов Компилятор переводит выражения запроса в цепочку вызовов расширяющих методов. varquery = fromname in names wherename.Length== 5 orderbyname selectname.ToUpper(); varquery= names.Where (name=> name.Length== 5) .OrderBy(name=> name) .Select (name=> name.ToUpper());
Делегаты Func Чтобы объявить метод LINQ, с параметром-делегатом, нужно указать тип параметра. publicstaticIEnumerable<TSource> Where<TSource> (thisIEnumerable<TSource> source, Func<TSource, bool> predicate); Для указания типа параметров используются обобщенный делегат Func, объявленный в пространстве имен System. publicdelegateTResultFunc<in T, outTResult>(T arg); Делегат перегружен и может принимать от 0 до 16 входных параметров-типов (T1, T2, T3,…).
Запросы Where() и Select() Where() – фильтр Пример: оставить только четные числа IEnumerable<int> result = m.Where(a => a % 2 == 0); Пример: оставить только числа, стоящие на четных местах IEnumerable<int> result = m.Where((a, i) => i % 2 == 0); Select() – проекция Пример:увеличить все числа в 1000 раз IEnumerable<int> result = m.Select(a => a * 1000 ); И оба вместе: varresult = m.Where(a => a % 2 == 0).Select(a => a * 1000 );
Самостоятельно • Реализовать итератор, который позволит проходить любой целый массив в обратном порядке. • Реализовать обобщенный итератор, который позволит проходить любой массив в обратном порядке. • Сделать обобщенный итератор, который обходит двумерный массив по столбцам. • Объявить итератор, который получает один целочисленный массив в качестве аргумента и вырабатывает все уникальные значения из входного массива. { 2, 3, 4, 3 ,3, 1 ,2 } => {2, 3, 4, 1} • Объявить итератор, который получает два целочисленных массива в качестве аргументов и вырабатывает только те значения, которые есть в первом массиве и в то же время отсутствуют во втором массиве. {1, 2, 3, 5, 6}, {4, 5, 1 } => {2, 3, 6}