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

where <условие 1> [where <условие 2> ...]

Например, если в предыдущем примере требуется отобрать людей, год рождения которых больше 1980 и меньше 2000, то условие отбора, реализованное по первой схеме, можно записать в виде:

where p.YearOfBirth > 1980 && p.YearOfBirth < 2000

а по второй схеме в виде:

where p.YearOfBirth > 1980 where p.YearOfBirth < 2000

При применении второй схемы несколько блоков where объединяются логическим оператором «И». Поэтому вторая схема имеет меньшие возможности по применению.

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

Пример: отобрать людей, фамилия которых начинается на букву «И», а год рождения нечетный.

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 = "Новокузнецк" };

People[] Result = (from p in Peoples

where p.Surname.StartsWith("И") && p.YearOfBirth % 2 == 1 select p).ToArray();

// Result = {[Иванов, 1971, Псков]}

9.2.4 orderby : использование сортировки

Сортировка позволяет расположить получаемые данные в требуемом порядке. Как правило, сортировка осуществляется по возрастанию или по убыванию значений данных, однако нет никаких ограничений на реализацию сортировки данных любым требуемым способом.

Для обеспечения сортировки в запрос вводится конструкция вида:

orderby <правило сортировки> [ascending | descending]

148

Как правило, указание признака сортировки размещается после определения условий отбора (см. общую схему в разделе 9.2.1).

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

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 = "Новокузнецк" };

People[] Result = (from p in Peoples

where p.YearOfBirth > 1980 orderby p.Surname

select p).ToArray();

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

Вкачестве правила сортировки может выступать не только <переменная диапазона>, но и различные выражения.

Пример: отобрать людей, фамилия которых не начинается на букву «И», и вывести их в порядке убывания столетия рождения.

People[] Result = (from p in Peoples

where !p.Surname.StartsWith("И") orderby p.YearOfBirth / 100 descending select p).ToArray();

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

Следует отметить, что если есть данные, имеющие одно и то же значение с точки зрения <правило сортировки>, то они выводятся в порядке их расположения в <источнике данных> (например, данные о втором и третьем человеке в предыдущем примере).

Сортировка результатов запроса может осуществляться по нескольким правилам. В этом случае пары «правило – направление» перечисляются через запятую.

Алгоритм сортировки по нескольким правилам следующий. Изначально все данные сортируются по первому правилу. Если некоторая группа данных имеет одинаковое значение с точки зрения первого правила сортировки, то эта группа сортируется по второму правилу, и т.д.

Пример: отобрать людей, родившихся в 20 веке, и вывести их в порядке убывания года рождения. При равенстве у нескольких людей года рождения, выводить их в алфавитном порядке фамилий.

149

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 = "Новокузнецк" };

People[] Result = (from p in Peoples

where p.YearOfBirth > 1900 && p.YearOfBirth <= 2000 orderby p.YearOfBirth descending, p.Surname

select p).ToArray();

// Result = {[Петров, 1999, Москва], [Иванов, 1980, Новокузнецк], [Попов, 1980, Новокузнецк], [Степанов, 1980, Москва], [Иванов, 1971, Псков]}

9.2.5 select : определение возвращаемого значения

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

Пример 1: получить в виде одномерного массива года рождения людей.

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 = "Новокузнецк" };

int[] Result = (from p in Peoples

select p.YearOfBirth).ToArray(); // Result = {1980, 1999, 1971, 1980, 2001, 1980}

150

Пример 2: получить в виде одномерного массива возрасты людей на начало 21 века (считать год рождения за целый год), отсортированные в порядке возрастания.

int[] Result = (from p in Peoples

where p.YearOfBirth <= 2000 orderby 2001 - p.YearOfBirth

select 2001 - p.YearOfBirth).ToArray(); // Result = {2, 21, 21, 21, 30}

Пример 3: создать класс, включающий фамилию человека и возраст на начало 21 века (считать год рождения за целый год). Сформировать массив элементов данного класса на основе исходного массива.

class ShortPeople

{

public string Surname; public int Age2001;

}

ShortPeople[] Result = (from p in Peoples where p.YearOfBirth <= 2000

select new ShortPeople() { Surname = p.Surname, Age2001 = 2001 - p.YearOfBirth }).ToArray();

// Result = {[Иванов, 21], [Петров, 2], [Иванов, 30], [Степанов, 21], [Попов, 21]}

Пример 4: реализовать пример 3 без создания нового класса.

var Result = (from p in Peoples

where p.YearOfBirth <= 2000 select new { Surname = p.Surname,

Age2001 = 2001 - p.YearOfBirth }).ToArray(); // Result = {[Иванов, 21], [Петров, 2], [Иванов, 30],

[Степанов, 21], [Попов, 21]}

В примере 4 создается анонимный тип, имеющий поле Surname строкового типа и целочисленное поле Age2001. Выполнение отбора может быть реализовано, например, таким образом:

foreach (var p in Result)

{

// p.Surname, p.Age2001 – доступ к полям объекта

}

9.2.1 group : группировка данных

Группировка позволяет сгруппировать данные в результате запроса по некоторому признаку (ключу). Поэтому типом элемента результата запроса является интерфейс IGrouping<TKey, TElement>, хранящий ключ типа TKey (доступ к ко-

151

1980,
Result_TB

торому осуществляется через свойство Key) и коллекцию элементов, относящихся к данному ключу (в виде интерфейса IEnumerable<TElement>).

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

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

Оператор group применяется вместо оператора select.

<возвращаемые данные> формируются по тем же правилам, что и в опера-

торе select.

<ключ группировки>, как правило, связан с <переменной диапазона>.

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

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

класса TextBox.

People[] Peoples = new People[6];

Peoples[0] = new People() { Surname = "Иванов", YearOfBirth = 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 = "Новокузнецк" };

var Result = from p in Peoples orderby p.City, p.Surname group p by p.City;

Result_TB.Clear();

foreach (var group in Result)

{

Result_TB.AppendText(group.Key + "\n"); foreach (var p in group)

Result_TB.AppendText(" "+p.Surname + "\n");

}

Результат будет выведен в виде:

Москва

Петров

Степанов

Новокузнецк

Антонов

Иванов

152

Попов

Псков

Иванов

Рассмотрим более подробно формирование запроса, его выполнение и вывод результата. При формировании запроса с помощью оператора

orderby p.City, p.Surname

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

Далее в операторе

group p by p.City

производится собственно отбор людей с группировкой по ключу, которым является название города проживания.

Так как результат запроса имеет двухуровневую структуру (город-люди), то для вывода результата требуется использование двух вложенных циклов. Первый цикл

foreach (var group in Result)

перебирает все группы, имеющиеся в результате запроса (и выводит название города с помощью group.Key). Второй цикл

foreach (var p in group)

перебирает всех людей в группе и выводит их фамилии.

Группировка может производиться и по нескольким ключам. В этом случае используется составной ключ, создаваемый с помощью анонимного типа или именованного типа для хранения элементов ключа.

Пример: сгруппировать данные о людях по городу их проживания и году рождения и вывести в алфавитном порядке названий городов и увеличения года рождения. В пределах каждой группы выводить людей в алфавитном порядке фамилий. Вывод осуществлять в компонент Result_TB класса TextBox.

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 = "Новокузнецк" };

153