Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций (C#).pdf
Скачиваний:
39
Добавлен:
25.03.2016
Размер:
2.43 Mб
Скачать

Продолжение таблицы 9.1

Наименование

Описание

Intersect<TSource>

Находит элементы, одинаковые в двух последовательно-

(IEnumerable

стях. Например:

<TSource> second)

 

 

int[] Mas1 = { 6, 4, 8, -5, 9 };

 

int[] Mas2 = { 6, -4, -8, -5, 9 };

 

int[] Mas3 = Mas1.Intersect(Mas2).ToArray();

 

// Mas3 = { 6, -5, 9 }

Union<TSource>

Объединяет две последовательности. Например:

(IEnumerable

 

<TSource> second)

int[] Mas1 = { 6, 4, 8, -5, 9 };

 

int[] Mas2 = { 6, -4, -8, -5, 9 };

 

int[] Mas3 = Mas1.Union(Mas2).ToArray();

 

// Mas3 = { 6, 4, 8, -5, 9, -4, -8 }

 

 

OrderBy

Сортирует по возрастанию/убыванию элементы последо-

<TSource, TKey>

вательности в соответствии со значением ключа, выдава-

(Func<TSource,

емого функцией keySelector. Например:

TKey> keySelector)

 

 

int[] Mas1 = { 6, 4, 8, 5, 9 };

OrderByDescending

int[] Mas2 =

<TSource, TKey>

Mas1.OrderBy(Value => Value % 3).ToArray();

(Func<TSource,

// Mas2 = { 6, 9, 4, 8, 5}

TKey> keySelector)

int[] Mas3 =

 

 

Mas1.OrderByDescending(

 

Value => Value % 3).ToArray();

 

// Mas3 = { 8, 5, 4, 6, 9}

Reverse<TSource>()

Изменяет порядок элементов последовательности на про-

 

тивоположный. Например:

 

int[] Mas1 = { 6, 4, 8, 5, 9 };

 

int[] Mas2 = Mas1.Reverse().ToArray();

 

// Mas2 = {9, 5, 8, 4, 6}

9.2 Построение запросов на LINQ

9.2.1 Общая структура запроса

Формальная структура запроса на LINQ имеет вид:

<переменная запроса> = from <переменная диапазона> in <источник данных> [where <условие, дающее логическое значение>]

[orderby <правило сортировки> [<направление сортировки>]] {select <возвращаемые данные> |

[group <возвращаемые данные> by <ключ группировки>]};

144

где:

<переменная запроса> – переменная, в которой хранится ссылка на правила запроса и с использованием которой можно будет выполнить запрос и получить доступ к возвращаемым результатам. Должна быть одной из форм интерфейса IEnumerable<T>. Может быть объявлена как var;

<переменная диапазона> – идентификатор, который используется внутри запроса для обращения к требуемым данным;

<источник данных> – должен поддерживать интерфейс IEnumerable<T>. По

<источнику

данных>

автоматически

определяется

тип

<переменной диапазона>;

 

 

 

<условие, дающее логическое значение> – условие, позволяющее из обще-

го набора данных отобрать требуемые. Часто в условии используется

<переменная диапазона>;

<правило сортировки> – данные, по значениям которых будет осуществляться сортировка. Могут получаться на основе построения выражений. Часто использу-

ется <переменная диапазона>;

<направление сортировки> – слова «ascending» или «descending», опре-

деляющие сортировку по возрастанию и убыванию, соответственно. По умолча-

нию используется сортировка по возрастанию, поэтому слово «ascending» можно не использовать;

<возвращаемые данные> – данные, которые будут записаны в

<переменную запроса>. Часто используется <переменная диапазона>;

<ключ группировки> – данные, по которым будут осуществлена группировка. Часто задается с использованием <переменной диапазона>.

9.2.2 Простой запрос

Для иллюстрации построения простого запроса решим следующую задачу: отобрать из целочисленного массива элементы, значение которых большие 51.

string s = "";

int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1

where elem > 5 select elem;

foreach (var elem in Mas2)

s += elem + " "; // s = “6 8 9 ”

Формирование запроса и его выполнение – две независимые процедуры.

Так в примере, приведенном выше, команда var Mas2 = ... выполняет только формированием запроса. При этом никакого отбора данных еще не производиться. Чтобы убедиться в этом, изменим программу следующим образом:

1 Использование запросов на LINQ имеет смысл, когда требуется извлечь часть данных из их общей совокупности. Поэтому уже в примере простейшего запроса будет использоваться условие отбора.

145

string s = "";

int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1

where elem > 5 select elem;

Mas1[0] = 3;

foreach (var elem in Mas2)

s += elem + " "; // s = “8 9 ”

Таким образом, выполнение запроса осуществляется только при получении данных из <переменной запроса>.

Одна и та же <переменная запроса> может использоваться несколько раз, и при этом выдавать разные результаты, если <источник данных> между выполнением запросов был изменен. Например:

string s = "";

int[] Mas1 = { 6, 4, 8, 5, 9 }; var Mas2 = from elem in Mas1

where elem > 5 select elem;

foreach (var elem in Mas2)

s += elem + " "; // s = “6 8 9 ” Mas1[0] = 3;

s = "";

foreach (var elem in Mas2)

s += elem + " "; // s = “8 9 ”

В приведенных выше примерах использовалось неявное типизирование переменных с использованием var (как при описании запроса, так и при его выполнении).

Однако типы всех переменных могут быть описаны явно. При этом <переменная запроса> должна быть описана как одна из форм интерфейса IEnumerable<T>, где <T> вытекает из результата, указанного в блоке select. Тип <переменной диапазона> должен соответствовать элементу <источника данных> и тоже может быть задан явно. Также тип <T> должна иметь переменная, используемая при выполнении запроса. Например:

string s = "";

int[] Mas1 = { 6, 4, 8, 5, 9 }; IEnumerable<int> Mas2 = from int elem in Mas1

where elem > 5 select elem;

foreach (int elem in Mas2)

s += elem + " "; // s = “6 8 9 ”

Элементами в <источника данных> могут быть не только простые типы, но и объекты любого класса. Для дальнейшего рассмотрения примеров построения запросов будет использоваться класс, описывающий человека и включающий: фами-

146

лию, год рождения, город проживания. Реализация данного класса и формирование массива людей имеет вид1:

class People

{

public string Surname; public int YearOfBirth; public string City;

}

People[] Peoples = new People[6];

Peoples[0] = new People() { Surname = "Иванов", YearOfBirth = 1980, City = "Новокузнецк" };

Peoples[1] = new People() { Surname = "Петров", YearOfBirth = 1999, City = "Москва" };

Peoples[2] = new People() { Surname = "Иванов", YearOfBirth = 1971, City = "Псков" };

Peoples[3] = new People() { Surname = "Степанов", YearOfBirth = 1980, City = "Москва" };

Peoples[4] = new People() { Surname = "Антонов", YearOfBirth = 2001, City = "Новокузнецк" };

Peoples[5] = new People() { Surname = "Попов", YearOfBirth = 1980, City = "Новокузнецк" };

Пример: отобрать из массива людей, которые родились позднее 1980 года.

People[] Result = (from p in Peoples

where p.YearOfBirth > 1980 select p).ToArray();

Врезультате выполнения данного запроса будет сформирован массив, включающий людей с индексами 1 («Петров») и 4 («Антонов»)2.

Вприведенном выше примере был использован метод ToArray() для получения результата запроса в виде одномерного массива.

9.2.3 where : использование условий отбора

В приведенных выше примерах уже использовалась простейшая форма условия отбора, состоящая из ключевого слова where и одного условия. Однако в большинстве случае условие отбора включает несколько взаимосвязанных условий, описание которых выполняется по одной из двух формальных схем:

where <условие 1> [<логический оператор> <условие 2> ...]

или

1 Для простоты все данные будут храниться в полях со спецификатором доступа public

2 Далее результаты запроса будут отображаться в виде:

// Result = {[Петров, 1999, Москва], [Антонов, 2001, Новокузнецк]}

147