Встроенная операция orderby также имеет аналог в виде extension-метода OrderBy. Покажем, как они работают на примере сортировки массива анонимных объектов.
var people = new[]{
new {Name="Alex Black", Position="Developer", Birth=new DateTime(1980,2,26) },
new {Name="Alex Ritter", Position="Boss", Birth=new DateTime(1969,3,15) },
new {Name="Peter Pann", Position="Manager", Birth=new DateTime(1980,9,12) },
new {Name="Joy Amore", Position="Referent", Birth=new DateTime(1990,6,27) },
new {Name="Jack O'Mule", Position="Referent", Birth=new DateTime(1990,4,2) },
new {Name="Jill Sweet", Position="Referent", Birth=new DateTime(1990,9,20) },
new {Name="Brad Show", Position="Developer", Birth=new DateTime(1980,2,26) }
};
var q = from p in people
orderby p.Position descending, p.Name
select p;
foreach (var v in q)
Console.WriteLine(v);
Последовательность объектов сортируется сначала по убыванию поля Position, затем по возрастанию поля Name. Вариант с использованием extension-методов выглядит следующим образом.
q = people.OrderByDescending (p => p.Position).ThenBy (p => p.Name);
Вы видите, что подход с ипользованием extension-методов по краткости не уступает подходу на основе интегрированных запросов, то есть, встроенных операций: from, select, orderby, descending.
Встроенные операции: group и by, а также их аналог в виде extension-метода GroupBy, позволяют создать группы объектов. Результат группировки — коллекция коллекций, то есть, последовательность групп, где каждая группа — это последовательность объектов. Каждой группе присваивается ключ (свойство Key). Для перечисления элементов групп нобходимо создать два вложенных цикла. Внешний цикл по группам (различаемым ключами), внутренний — по элементам внутри каждой группы.
var numbers = new [] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var gr = from n in numbers group n by n % 3;
Console.WriteLine("Test grouping");
foreach (var g in gr.ToArray()) // Вместо var можно подставить тип IGrouping<int, int>
{
Console.Write("\n Group # " + g.Key + ": ");
foreach (var v in g.ToArray())
Console.Write(v + ", ");
}
Пример выше разбивает массив целых чисел на три группы в зависимости от остатка деления на 3. Двойной цикл выводит все элементы с учетом деления на группы.
Test grouping
Group # 1: 1, 4, 7, 10,
Group # 2: 2, 5, 8,
Group # 0: 3, 6, 9,
Анализируя код, обратите внимание на свойство Key.
Задание. Попробуйте вычислить тип переменной gr (то есть, тип самой группы).
Ответ. Описатель var можно заменить описателем типа: IEnumerable<IGrouping<int,int>>. Если вывести на консоль имя типа, например: Console.WriteLine(gr.GetType().Name);, то вы увидите внутреннее имя типа: "GroupedEnumerable`3". Этим именем пользуется компилятор и здесь мы видим намек на три параметра. Если в окне отладчика проверить истинность утверждения: gr.GetType() == typeof(System.Linq.IGrouping<int, int, int>), то мы получим true. Но при попытке вставить это выражение в код программы компилятор выдаст ошибку.
Задание. Вычислите тип переменной g. Ответ. IGrouping<int, int>.
Следующий фрагмент реализует тот же самый запрос, но с помощью extension-метода GroupBy.
gr = numbers.GroupBy (n => n % 3); // Он заметно короче
Теперь покажем, как заменить цикл перебора элементов extension-методом ForEach.
Console.WriteLine("\nTest grouping (Extension)");
Array.ForEach (gr.ToArray(), x =>
{
Console.Write("\n Group # " + x.Key + ": ");
Array.ForEach (x.ToArray(), y => Console.Write(y + ", "));
});
Обратите внимание на следующие детали:
¨ Перечисление результатов группировки требует вызвать ForEach дважды.
¨ Для прохода вдоль последовательности gr, имеющей тип IEnumerable<IGrouping<int,int>>, необходимо привести ее к типу Array. Это делает extension-метод ToArray.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.