Файл: Справочник для опытных и как пособие для начинающих программистов. Компактдиск содержит исходные коды примеров из книги.doc
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 11.01.2024
Просмотров: 950
Скачиваний: 1
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Visual Studio 2010, закажем новый проект шаблона Windows Forms Application C#. Затем из панели элементов перенесем в форму текстовое поле. Далее через щелчок правой кнопкой мыши перейдем к вкладке программного кода (листинг 11.2).
Листинг 11.2. Извлечение данных из списков
// Решаем три различных задачи по выбору элементов (объектов) из списка
// с помощью стандартных запросов технологии LINQ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace Linq2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Text = "Технология LINQ"; textBox1.Multiline = true;
// ЗАДАЧА 1. Из списка строк выбрать нужные записи,
// задав условие выбора
textBox1.Text = "ЗАДАЧА 1: Из списка имен:\r\n";
// Объявление списка строк и его заполнение:
var Список = new List { "Витя", "Света", "Андрей",
"Лариса", "Маша", "Наташа" };
// или var Список = new List(); // список строк
// Список.Add("Витя"); Список.Add("Света"); Список.Add("Андрей");
// Список.Add("Лариса"); Список.Add("Маша"); Список.Add("Наташа");
// Некоторые манипуляции со списком:
int n = Список.Count; // количество элементов в списке
// Получение из списка третьего элемента (как в массиве):
string А = Список.ElementAt(4);
Boolean Ответ = Список.Remove("Лариса"); // - удаление из списка
// Преобразовать список в строковый массив:
string[] МассивСтрок = Список.ToArray();
foreach (var x in Список)
textBox1.Text = textBoxl.Text + x.ToStringf) + " ";
textBox1.Text += "\r\nвыбираем имена длиной четыре символа:\r\n";
// СписокВыбранныхИмен - это новый список, в который попадают
// выбранные строки в результате LINQ-запроса:
var СписокВыбранныхИмен = from Имя in Список
where Имя.Length ==4 // условие выбора
orderby Имя // сортировать список
select Имя;
// Вывод списка выбранных имен в текстовое поле textBox1:
foreach (var х in СписокВыбранныхИмен)
textBox1.Text = textBox1.Text + x.ToString(J + " ";
//----------------------------------------------------------------------------------------------------------------------
// ЗАДАЧА 2.
textBox1.Text +=
"\r\n\r\nЗАДАЧА 2: Из списка сотрудников предприятия " +
"выбираем некурящих для повышения зарплаты:\r\n\r\n";
// Заполняем список сотрудников:
List Сотрудники = new List{
new Сотрудник {Имя="Карапузова Ирина", Возраст=27, КуритЛи=true },
new Сотрудник {Имя="Зиборов Виктор", Возраст=47, KypитЛи=false },
new Сотрудник {Имя="Ломачинская Светлана", Возраст=31, KypитЛи=false },
new Сотрудник {Имя="Стороженко Светлана", Возраст=34, KypитЛи=false },
new Сотрудник {Имя="Еременко Татьяна", Возраст=22, КуритЛи= true },
new Сотрудник {Имя="Погребицкий Олег", Возраст=42, КуритЛи= true},
};
var СписокНекурящихСотрудников = from Сотрудник in Сотрудники
where Сотрудник.КуритЛи == false
orderby Сотрудник.Имя
select Сотрудник;
// Вывод списка некурящих сотрудников в текстовое поле textBox1:
foreach (var х in СписокНекурящихСотрудников)
textBox1.Text = textBox1.Text + string.Format("{0} - возраст " + "- {1}\r\n", х.Имя, x.Возраст);
//-------------------------------------------------------------------------------------------------------------------------------
// ЗАДАЧА 3.
textBox1.Text += "\г\пЗАДАЧА 3: Из списка студентов факультета " +
"выбираем двоечников:\r\n\r\n";
// Каждый элемент в списке содержит фамилию студента
// и полученные им текущие оценки:
List<Студент> Студенты = new List<Студент> {
new Студент {Фамилия="Зиборов",
Оценки= new List {5, 4, 4, 5}},
new Студент {Фамилия="Стороженко",
Оценки= new List {3, 3, 2, 3}},
new Студент {Фамилия="Ломачинская",
Оценки= new List {3, 4, 4, 5}},
new Студент {Фамилия="Погребицкий",
Оценки= new List {2, 4, 3, 2}},
new Студент {Фамилия="Левочкин",
Оценки= new List {3, 3, 4, 3}}
};
//Для доступа к внутреннему списку оценок предложение From используем два раза:
var СписокДвоечников = from Студент in Студенты
from Оценка in Студент.Оценки
where Оценка <= 2
orderby Студент.Фамилия
select new { Студент.Фамилия, Оценка };
foreach (var Студик in СписокДвоечников)
textBox1.Text += string.Format("Студент {0} " +
"имеет оценку: {1}\r\n", Студик.Фамилия, Студик.Оценка);
// Строка со студентом Погребицким выводится два раза,
// поскольку он имеет две двойки
}
}
// Объявляем класс, содержащий имя сотрудника, его возраст, а также информацию, курит ли он:
public class Сотрудник
{
public string Имя { get; set; }
public int Возраст { get; set; }
public bool КуритЛи { get; set; }
)
//Объявляем класс, содержащий фамилию студента и список полученных им оценок:
Public class Студент
{
public string Фамилия { get; set; }
public List Оценки { get; set; }
}
}
Первая задача довольно простая и очень похожа на задачи, которые мы решали с помощью технологии LINQ в предыдущем примере. Здесь, в этой новой задаче вместо массива имен требуется создать список имен, а далее из этого списка вы. брать имена длиной четыре символа. Решение этой задачи, построение LINQ-запроса аналогично решению задачи из предыдущего примера, отличие состоит лишь в применении синтаксиса манипуляций со списком типа List, а не с массивом. Здесь также приведены некоторые важные техники для манипуляции списком в частности получение элемента списка по указанному индексу (аналогия с массивом), удаление элемента, преобразование списка в строковый массив.
Вторая задача заключается в том, чтобы создать список сотрудников предприятия и из этого списка выбрать некоторых сотрудников по какому-либо признаку например тех, кто не курит. При создании списка объявлен класс Сотрудник, который содержит три свойства: Имя, Возраст и булеву переменную КуритЛи. В начале решения заполняем список сотрудников, а затем строим LINQ-запрос для заполнения списка некурящих сотрудников. Этот список выводим в текстовое поле textBox1, используя цикл foreach.
Третья задача немного сложнее. Требуется создать список студентов факультета, содержащий фамилию студента и список полученных им текущих оценок, т. е. список оценок должен быть "вложен" в список студентов. Из списка студентов необходимо выбрать тех, кто имеет в списке своих оценок хотя бы одну двойку. Для решения этой задачи вначале объявляем новый класс Студент, который имеет в качестве свойств класса фамилию студента и список (типа List) оценок. Далее в начале решения третьей задачи мы привели синтаксис заполнения списка студентов. Затем строим LINQ-запрос, где, поскольку нам необходимо искать элемент списка внутри "вложенного" списка, мы используем предложение From два раза. Поскольку студент Погребицкий имеет две двойки в списке своих текущих оценок, он в списке двоечников фигурирует дважды (рис. 11.2).
Рис. 11.2. Три LINQ-запроса к спискам данных
Убедиться в работоспособности программы можно, открыв решение Linq2.sln папки Linq2.
Пример 77. Группировка элементов списка с помощью LINQ-запроса
В данном примере используем стандартный шаблон LINQ-запроса для группивки элементов списка. Программа формирует список продуктов питания. Следует организовать такие LINQ-запросы, которые разделят искомый список на две уппы по критерию цены (больше или меньше 90 руб. за единицу) и вычислят среднюю цену по каждой группе продуктов.
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqЦеныНаПродукты. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим текстовое поле TextBox для вывода в него групп списка. В свойствах текстового поля разрешим ввод множества строк, для этого свойство Multiline переведем в состояние true. Затем на вкладке программного кода введем текст, представленный в листинге 11.3.
Листинг 11.3. Группировка элементов списка с помощью LINQ-запросов
//Программа формирует список некоторых продуктов питания. Первый LINQ-запрос
// группирует элементы списка по критерию цены: в первом списке оказываются
// продукты, цена за единицу которых меньше или равна 90 руб., а во втором,
// соответственно, больше 90 руб. Второй LINQ-запрос вычисляет среднюю цену
// продукта по каждой группе. Результаты запросов выводятся в текстовое поле
using System;
using System.Collections .Generic;
using System.Linq;
using System.Windows.Forms;
//Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqЦеныНаПродукты
{
public partial class Form1 : Form
public Form1()
{
InitializeComponent();
textBox1 .Multiline = true;
base.Text = "Группировка элементов списка с помощью LINQ-запроса";
// Заполняем список продуктов:
List<Пpoдукт> Продукты = new List<Пpoдукт>{
new Продукт {Наименование="Творог", Цена=112.50F },
new Продукт {Наименование="Хлеб", Цена=18.75F },
new Продукт {Наименование="Печенье", Цена=93.75F },
new Продукт {Наименование="Чай", Цена=76.25F },
new Продукт {Наименование="Мясо", Цена=150.00F },
new Продукт {Наименование="Гречка", Цена=62.50F },,
};
var Запрос1 = from П in Продукты
group П by new
{
Критерий = П.Цена > 90,
}
into g
select g;
var Запрос2 = from p in Продукты
group p by p.Цена > 90 into g
select new
{
g.Key,
СредЦенаПоГруппе = g.Average(p => p.Цена)
};
Single СредЦенаПоГруппе1 = Запрос2.ElementAt(0).СредЦенаПоГруппе;
Single СредЦенаПоГруппе2 = Запрос2.ElementAt(1).СредЦенаПоГруппе;
// Вывод результатов обоих запросов в текстовое поле:
foreach (var Группа in 3anpoc1)
{
if (Группа.Key.Критерий .== false)
textBox1.Text += "\r\nЦены 90 руб или меньше:";
else
textBox1.Text += "\r\nЦены больше 90 руб:";
foreach (var Прод in Группа)
{
textBox1.Text += String.Format("\r\n{0} - {1}", Прод.Наименование, Прод.Цена);
}
if (Группа.Key.Критерий == false)
textBox1.Text += String.Format(
"\r\nСредняя цена по данной группе = {0} руб.\r\n", СредЦенаПоГруппе2);
else
textBox1.Text += String.Format(
"\r\nСредняя цена по данной группе = {0} руб.\г\п", СредЦенаПоГруппе1);
}
}
}
public class Продукт
{
public String Наименование { get; set; }
public Single Цена { get; set; }
}
)
В начале программы формируем список продуктов питания. Для этого объявляем новый класс Продукт, в котором для каждого продукта задаем два поля: наименование продукта и его цену. После заполнения списка продуктов (для упрощения в этом списке всего шесть продуктов) задаем первый LINQ-запрос, обеспечивающий деление списка на две группы. Второй
LINQ-запрос вычисляет среднюю цену продукта по каждой группе. Вывод результатов обоих запросов организуем с помощью двух вложенных циклов foreach.
Фрагмент работы программы показан на рис. 11.3.
Рис. 11.3. Группировка списка с помощью LINQ-запросов
Убедиться в работоспособности программы можно, открыв решение LinqЦеныНаПродуктыю.sln папки LinqЦеныНаПродукты.
Пример 78. LINQ-запрос к словарю данных Dictionary
Замечательной структурой данных является словарь Dictionary. Он представит собой совокупность (коллекцию) ключей и значений. То есть каждый элемент (запись), добавляемый в словарь, состоит из значения Value и связанного с ним
ключа Key. Извлечение значения по его ключу происходит очень быстро, поскольку класс Dictionary<Key, Value> реализован как хэш-таблица. Каждый ключ словаре Dictionary<Key, Value> должен быть уникальным, т. е. единственным своем роде, эксклюзивным. При добавлении в коллекцию Dictionary очередного элемента так называемый компаратор проверяет на равенство уникальность нового ключа. Ключ не может быть пустым (null), а значение может, если тип значения Value является ссылочным типом. Возможно создание словаря, в котором не различается регистр символов. Использование словаря Dictionary может существенно повлиять на эффективность алгоритма, на простоту его понимания и легкость программной реализации.
Задача, решаемая в данном примере, состоит в том, чтобы продемонстрирова возможность выбора элементов из словаря данных Dictionary с помощью LINQ- запроса. В начале программы зададим массив сотрудников некого учреждения, затем массив сотрудников преобразуем в словарь Dictionary. Причем в качестве ключа к каждому элементу словаря зададим имя сотрудника, которое является уникальным. По ключу можно получить все остальные сведения о сотруднике, записанные в словарь. Кроме того, с помощью LINQ-запроса к словарю можно получать новую коллекцию сотрудников по какому-либо условию (предложение where). Здесь мы зададим выбор сотрудников, чей возраст превышает 33 года (возраст Иисуса Христа).
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Console Application, укажем имя Name — LinqDictionary. Затем на вкладке программного кода введем текст, представленный в листинге 11.4.
Листинг 11.4. Организация
LINQ-запроса к словарю Dictionary
// Задаем массив сотрудников учреждения. Из этого массива создаем словарь
// сотрудников, а в качестве ключа к этому словарю выбираем имя сотрудника.
//С помощью LINQ-запроса из массива сотрудников выбираем тех, чей возраст
// превышает 33 года. При выводе результата запроса на печать учитываем, что
//мы говорим "47 лет", но "34 года". То есть если из возраста
// вычесть число, кратное 10, то при остатке меньше 5 говорят,
// например, "34 года", а при остатке больше или равном 5 говорят "47 лет"
using System;
using System.Linq;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqDictionary
{
class Program
{
static void Main(string[] args)
{
Console.Title = "LINQ-запрос к словарю Dictionary";
// Создаем массив сотрудников учреждения:
var Сотрудники = new[] {
new {Имя = "Карапузова Ирина",» Возраст = 27, КуритЛи = true },
new {Имя = "Зиборов Виктор", Возраст = 47, КуритЛи = false },
new {Имя = "Ломачинская Светлана", Возраст = 31, КуритЛи = false },
new {Имя = "Стороженко Светлана", Возраст = 34, КуритЛи = false },
new {Имя = "Еременко Татьяна", Возраст = 22, КуритЛи = true },
new {Имя = "Погребицкий Олег", Возраст = 42, КуритЛи = true }
};
// Доступ к элементу массива Сотрудники можем иметь через его индекс:
var t = Сотрудники [2] ;
//Строим LINQ-запрос к массиву сотрудников; выбираем тех,
// чей возраст больше 33 лет:
// var СписокВзрослыхСотрудников = from Сотрудник in Сотрудники
// where Сотрудник.Возраст >= 33
// orderby Сотрудник.Имя
// select Сотрудник;
//Из массива сотрудников создаем словарь сотрудников, в котором
// ключом является имя сотрудника:
var СловарьСотрудников = Сотрудники.ToDictionary(Ключ => Ключ.Имя);
// В этом случае очень удобным становится доступ к сведениям
//о сотруднике по его имени:
Boolean КуритЛиЗиборов = СловарьСотрудников
["Зиборов Виктор"].КуритЛи;
int ВозрастЗиборова = СловарьСотрудников["Зиборов Виктор"].Возраст;
Console.WriteLine("Сотруднику Зиборову Виктору - {0} лет\n", ВозрастЗиборова);
// Строим LINQ-запрос к словарю сотрудников; выбираем тех,
// чей возраст больше 33 лет: var СписокВзрослыхСотрудников =
from Сотрудник in СловарьСотрудников
where Сотрудник.Value.Возраст >= 33
orderby Сотрудник.Value.Имя
select new
{
Сотрудник.Key, Сотрудник.Value.Возраст,
ЛетИлиГода = Сотрудник.Value.Возраст - 10F *
Math.Truncate(Сотрудник.Value.Возраст / 10F) >= 5
};
// Вывод результата запроса на консоль:
Console.WriteLine("Список сотрудников, старше 33 лет:");
foreach (var x in СписокВзрослыхСотрудников)
Console.WriteLine("{0}, возраст - {1} {2} ", x.Key, x.Возраст, х.ЛетИлиГода ? "лет" : "года");
Console.ReadKey();
}
}
}
Представленный текст программы очевиден. Вначале задаем массив сотрудников учреждения, в этом массиве всего 6 элементов. В комментарии показано, как можно организовать LINQ-запрос к заданному массиву. Далее массив конвертируем в словарь сотрудников, задавая в качестве ключа имя сотрудника. Затем организуем LINQ-запрос к словарю Dictionary, выбираем в новую коллекцию (список тех, чей возраст превышает 33 года. Учитываем, что при выводе на консоль списка выбранных сотрудников мы говорим "47 лет", но "34 года". То есть если из возрас. та вычесть число, кратное 10, то при остатке меньше 5 говорят, например, "34 года", а при остатке больше или равном 5 говорят "47 лет". Число, кратное 10, мы вычисляем, используя функцию Math.Truncate, которая возвращает целую часть числа, поданную на ее вход. В этом алгоритме мы использовали булеву переменную ЛетИлиГода, которая определяет (по принципу "да" или "нет") следует писать "лет" или "года".
Результат работы программы показан на рис. 11.4.
Рис. 11.4. Запрос к словарю данных на "взрослых" сотрудников
Убедиться в работоспособности программы можно, открыв решение LinqDictionary.sln папки LinqDictionary.
Пример 79. Создание XML-документа методами классов пространства имен System.Xml.Linq
Кроме пространства имен System.Xml, содержащего классы для обработк XML-документов, в Visual С#2010 имеем пространство имен System.Xml.Linq, содержащее классы, которые позволяют легко и эффективно изменять документы XML, а также организовывать LINQ-запросы. В данном примере оформим сведения о наших повседневных телефонных контактах в XML-документ. Этот документ будет иметь интуитивно понятную структуру: имя контакта, домашний и мольный телефоны. Создав такой XML-документ и получив соответствующий XML -файл, его очень удобно просмотреть в MS Excel в виде таблицы, содержащей три столбца: имя контакта, домашний телефон и мобильный. Попутно обсудим структуру XML-документа.
Итак, запустим среду Visual Studio 2010, выберем проект шаблона Console Арplication, укажем имя Name — LinqСоздатьXML-документ. Затем на вкладке программного кода введем текст, представленный в листинге 11.5.
Листинг 11.5. Создание
Листинг 11.2. Извлечение данных из списков
// Решаем три различных задачи по выбору элементов (объектов) из списка
// с помощью стандартных запросов технологии LINQ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace Linq2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Text = "Технология LINQ"; textBox1.Multiline = true;
// ЗАДАЧА 1. Из списка строк выбрать нужные записи,
// задав условие выбора
textBox1.Text = "ЗАДАЧА 1: Из списка имен:\r\n";
// Объявление списка строк и его заполнение:
var Список = new List
"Лариса", "Маша", "Наташа" };
// или var Список = new List
// Список.Add("Витя"); Список.Add("Света"); Список.Add("Андрей");
// Список.Add("Лариса"); Список.Add("Маша"); Список.Add("Наташа");
// Некоторые манипуляции со списком:
int n = Список.Count; // количество элементов в списке
// Получение из списка третьего элемента (как в массиве):
string А = Список.ElementAt
Boolean Ответ = Список.Remove("Лариса"); // - удаление из списка
// Преобразовать список в строковый массив:
string[] МассивСтрок = Список.ToArray();
foreach (var x in Список)
textBox1.Text = textBoxl.Text + x.ToStringf) + " ";
textBox1.Text += "\r\nвыбираем имена длиной четыре символа:\r\n";
// СписокВыбранныхИмен - это новый список, в который попадают
// выбранные строки в результате LINQ-запроса:
var СписокВыбранныхИмен = from Имя in Список
where Имя.Length ==4 // условие выбора
orderby Имя // сортировать список
select Имя;
// Вывод списка выбранных имен в текстовое поле textBox1:
foreach (var х in СписокВыбранныхИмен)
textBox1.Text = textBox1.Text + x.ToString(J + " ";
//----------------------------------------------------------------------------------------------------------------------
// ЗАДАЧА 2.
textBox1.Text +=
"\r\n\r\nЗАДАЧА 2: Из списка сотрудников предприятия " +
"выбираем некурящих для повышения зарплаты:\r\n\r\n";
// Заполняем список сотрудников:
List
new Сотрудник {Имя="Карапузова Ирина", Возраст=27, КуритЛи=true },
new Сотрудник {Имя="Зиборов Виктор", Возраст=47, KypитЛи=false },
new Сотрудник {Имя="Ломачинская Светлана", Возраст=31, KypитЛи=false },
new Сотрудник {Имя="Стороженко Светлана", Возраст=34, KypитЛи=false },
new Сотрудник {Имя="Еременко Татьяна", Возраст=22, КуритЛи= true },
new Сотрудник {Имя="Погребицкий Олег", Возраст=42, КуритЛи= true},
};
var СписокНекурящихСотрудников = from Сотрудник in Сотрудники
where Сотрудник.КуритЛи == false
orderby Сотрудник.Имя
select Сотрудник;
// Вывод списка некурящих сотрудников в текстовое поле textBox1:
foreach (var х in СписокНекурящихСотрудников)
textBox1.Text = textBox1.Text + string.Format("{0} - возраст " + "- {1}\r\n", х.Имя, x.Возраст);
//-------------------------------------------------------------------------------------------------------------------------------
// ЗАДАЧА 3.
textBox1.Text += "\г\пЗАДАЧА 3: Из списка студентов факультета " +
"выбираем двоечников:\r\n\r\n";
// Каждый элемент в списке содержит фамилию студента
// и полученные им текущие оценки:
List<Студент> Студенты = new List<Студент> {
new Студент {Фамилия="Зиборов",
Оценки= new List
new Студент {Фамилия="Стороженко",
Оценки= new List
new Студент {Фамилия="Ломачинская",
Оценки= new List
new Студент {Фамилия="Погребицкий",
Оценки= new List
new Студент {Фамилия="Левочкин",
Оценки= new List
};
//Для доступа к внутреннему списку оценок предложение From используем два раза:
var СписокДвоечников = from Студент in Студенты
from Оценка in Студент.Оценки
where Оценка <= 2
orderby Студент.Фамилия
select new { Студент.Фамилия, Оценка };
foreach (var Студик in СписокДвоечников)
textBox1.Text += string.Format("Студент {0} " +
"имеет оценку: {1}\r\n", Студик.Фамилия, Студик.Оценка);
// Строка со студентом Погребицким выводится два раза,
// поскольку он имеет две двойки
}
}
// Объявляем класс, содержащий имя сотрудника, его возраст, а также информацию, курит ли он:
public class Сотрудник
{
public string Имя { get; set; }
public int Возраст { get; set; }
public bool КуритЛи { get; set; }
)
//Объявляем класс, содержащий фамилию студента и список полученных им оценок:
Public class Студент
{
public string Фамилия { get; set; }
public List
}
}
Первая задача довольно простая и очень похожа на задачи, которые мы решали с помощью технологии LINQ в предыдущем примере. Здесь, в этой новой задаче вместо массива имен требуется создать список имен, а далее из этого списка вы. брать имена длиной четыре символа. Решение этой задачи, построение LINQ-запроса аналогично решению задачи из предыдущего примера, отличие состоит лишь в применении синтаксиса манипуляций со списком типа List, а не с массивом. Здесь также приведены некоторые важные техники для манипуляции списком в частности получение элемента списка по указанному индексу (аналогия с массивом), удаление элемента, преобразование списка в строковый массив.
Вторая задача заключается в том, чтобы создать список сотрудников предприятия и из этого списка выбрать некоторых сотрудников по какому-либо признаку например тех, кто не курит. При создании списка объявлен класс Сотрудник, который содержит три свойства: Имя, Возраст и булеву переменную КуритЛи. В начале решения заполняем список сотрудников, а затем строим LINQ-запрос для заполнения списка некурящих сотрудников. Этот список выводим в текстовое поле textBox1, используя цикл foreach.
Третья задача немного сложнее. Требуется создать список студентов факультета, содержащий фамилию студента и список полученных им текущих оценок, т. е. список оценок должен быть "вложен" в список студентов. Из списка студентов необходимо выбрать тех, кто имеет в списке своих оценок хотя бы одну двойку. Для решения этой задачи вначале объявляем новый класс Студент, который имеет в качестве свойств класса фамилию студента и список (типа List) оценок. Далее в начале решения третьей задачи мы привели синтаксис заполнения списка студентов. Затем строим LINQ-запрос, где, поскольку нам необходимо искать элемент списка внутри "вложенного" списка, мы используем предложение From два раза. Поскольку студент Погребицкий имеет две двойки в списке своих текущих оценок, он в списке двоечников фигурирует дважды (рис. 11.2).
Рис. 11.2. Три LINQ-запроса к спискам данных
Убедиться в работоспособности программы можно, открыв решение Linq2.sln папки Linq2.
Пример 77. Группировка элементов списка с помощью LINQ-запроса
В данном примере используем стандартный шаблон LINQ-запроса для группивки элементов списка. Программа формирует список продуктов питания. Следует организовать такие LINQ-запросы, которые разделят искомый список на две уппы по критерию цены (больше или меньше 90 руб. за единицу) и вычислят среднюю цену по каждой группе продуктов.
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Windows Forms Application, укажем имя Name — LinqЦеныНаПродукты. Далее, попав в конструктор формы, из панели элементов Toolbox перетащим текстовое поле TextBox для вывода в него групп списка. В свойствах текстового поля разрешим ввод множества строк, для этого свойство Multiline переведем в состояние true. Затем на вкладке программного кода введем текст, представленный в листинге 11.3.
Листинг 11.3. Группировка элементов списка с помощью LINQ-запросов
//Программа формирует список некоторых продуктов питания. Первый LINQ-запрос
// группирует элементы списка по критерию цены: в первом списке оказываются
// продукты, цена за единицу которых меньше или равна 90 руб., а во втором,
// соответственно, больше 90 руб. Второй LINQ-запрос вычисляет среднюю цену
// продукта по каждой группе. Результаты запросов выводятся в текстовое поле
using System;
using System.Collections .Generic;
using System.Linq;
using System.Windows.Forms;
//Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqЦеныНаПродукты
{
public partial class Form1 : Form
public Form1()
{
InitializeComponent();
textBox1 .Multiline = true;
base.Text = "Группировка элементов списка с помощью LINQ-запроса";
// Заполняем список продуктов:
List<Пpoдукт> Продукты = new List<Пpoдукт>{
new Продукт {Наименование="Творог", Цена=112.50F },
new Продукт {Наименование="Хлеб", Цена=18.75F },
new Продукт {Наименование="Печенье", Цена=93.75F },
new Продукт {Наименование="Чай", Цена=76.25F },
new Продукт {Наименование="Мясо", Цена=150.00F },
new Продукт {Наименование="Гречка", Цена=62.50F },,
};
var Запрос1 = from П in Продукты
group П by new
{
Критерий = П.Цена > 90,
}
into g
select g;
var Запрос2 = from p in Продукты
group p by p.Цена > 90 into g
select new
{
g.Key,
СредЦенаПоГруппе = g.Average(p => p.Цена)
};
Single СредЦенаПоГруппе1 = Запрос2.ElementAt(0).СредЦенаПоГруппе;
Single СредЦенаПоГруппе2 = Запрос2.ElementAt(1).СредЦенаПоГруппе;
// Вывод результатов обоих запросов в текстовое поле:
foreach (var Группа in 3anpoc1)
{
if (Группа.Key.Критерий .== false)
textBox1.Text += "\r\nЦены 90 руб или меньше:";
else
textBox1.Text += "\r\nЦены больше 90 руб:";
foreach (var Прод in Группа)
{
textBox1.Text += String.Format("\r\n{0} - {1}", Прод.Наименование, Прод.Цена);
}
if (Группа.Key.Критерий == false)
textBox1.Text += String.Format(
"\r\nСредняя цена по данной группе = {0} руб.\r\n", СредЦенаПоГруппе2);
else
textBox1.Text += String.Format(
"\r\nСредняя цена по данной группе = {0} руб.\г\п", СредЦенаПоГруппе1);
}
}
}
public class Продукт
{
public String Наименование { get; set; }
public Single Цена { get; set; }
}
)
В начале программы формируем список продуктов питания. Для этого объявляем новый класс Продукт, в котором для каждого продукта задаем два поля: наименование продукта и его цену. После заполнения списка продуктов (для упрощения в этом списке всего шесть продуктов) задаем первый LINQ-запрос, обеспечивающий деление списка на две группы. Второй
LINQ-запрос вычисляет среднюю цену продукта по каждой группе. Вывод результатов обоих запросов организуем с помощью двух вложенных циклов foreach.
Фрагмент работы программы показан на рис. 11.3.
Рис. 11.3. Группировка списка с помощью LINQ-запросов
Убедиться в работоспособности программы можно, открыв решение LinqЦеныНаПродуктыю.sln папки LinqЦеныНаПродукты.
Пример 78. LINQ-запрос к словарю данных Dictionary
Замечательной структурой данных является словарь Dictionary. Он представит собой совокупность (коллекцию) ключей и значений. То есть каждый элемент (запись), добавляемый в словарь, состоит из значения Value и связанного с ним
ключа Key. Извлечение значения по его ключу происходит очень быстро, поскольку класс Dictionary<Key, Value> реализован как хэш-таблица. Каждый ключ словаре Dictionary<Key, Value> должен быть уникальным, т. е. единственным своем роде, эксклюзивным. При добавлении в коллекцию Dictionary очередного элемента так называемый компаратор проверяет на равенство уникальность нового ключа. Ключ не может быть пустым (null), а значение может, если тип значения Value является ссылочным типом. Возможно создание словаря, в котором не различается регистр символов. Использование словаря Dictionary может существенно повлиять на эффективность алгоритма, на простоту его понимания и легкость программной реализации.
Задача, решаемая в данном примере, состоит в том, чтобы продемонстрирова возможность выбора элементов из словаря данных Dictionary с помощью LINQ- запроса. В начале программы зададим массив сотрудников некого учреждения, затем массив сотрудников преобразуем в словарь Dictionary. Причем в качестве ключа к каждому элементу словаря зададим имя сотрудника, которое является уникальным. По ключу можно получить все остальные сведения о сотруднике, записанные в словарь. Кроме того, с помощью LINQ-запроса к словарю можно получать новую коллекцию сотрудников по какому-либо условию (предложение where). Здесь мы зададим выбор сотрудников, чей возраст превышает 33 года (возраст Иисуса Христа).
Для решения этой задачи запустим Visual Studio 2010 и выберем проект шаблона Console Application, укажем имя Name — LinqDictionary. Затем на вкладке программного кода введем текст, представленный в листинге 11.4.
Листинг 11.4. Организация
LINQ-запроса к словарю Dictionary
// Задаем массив сотрудников учреждения. Из этого массива создаем словарь
// сотрудников, а в качестве ключа к этому словарю выбираем имя сотрудника.
//С помощью LINQ-запроса из массива сотрудников выбираем тех, чей возраст
// превышает 33 года. При выводе результата запроса на печать учитываем, что
//мы говорим "47 лет", но "34 года". То есть если из возраста
// вычесть число, кратное 10, то при остатке меньше 5 говорят,
// например, "34 года", а при остатке больше или равном 5 говорят "47 лет"
using System;
using System.Linq;
// Другие директивы using удалены, поскольку они не используются в данной программе
namespace LinqDictionary
{
class Program
{
static void Main(string[] args)
{
Console.Title = "LINQ-запрос к словарю Dictionary";
// Создаем массив сотрудников учреждения:
var Сотрудники = new[] {
new {Имя = "Карапузова Ирина",» Возраст = 27, КуритЛи = true },
new {Имя = "Зиборов Виктор", Возраст = 47, КуритЛи = false },
new {Имя = "Ломачинская Светлана", Возраст = 31, КуритЛи = false },
new {Имя = "Стороженко Светлана", Возраст = 34, КуритЛи = false },
new {Имя = "Еременко Татьяна", Возраст = 22, КуритЛи = true },
new {Имя = "Погребицкий Олег", Возраст = 42, КуритЛи = true }
};
// Доступ к элементу массива Сотрудники можем иметь через его индекс:
var t = Сотрудники [2] ;
//Строим LINQ-запрос к массиву сотрудников; выбираем тех,
// чей возраст больше 33 лет:
// var СписокВзрослыхСотрудников = from Сотрудник in Сотрудники
// where Сотрудник.Возраст >= 33
// orderby Сотрудник.Имя
// select Сотрудник;
//Из массива сотрудников создаем словарь сотрудников, в котором
// ключом является имя сотрудника:
var СловарьСотрудников = Сотрудники.ToDictionary(Ключ => Ключ.Имя);
// В этом случае очень удобным становится доступ к сведениям
//о сотруднике по его имени:
Boolean КуритЛиЗиборов = СловарьСотрудников
["Зиборов Виктор"].КуритЛи;
int ВозрастЗиборова = СловарьСотрудников["Зиборов Виктор"].Возраст;
Console.WriteLine("Сотруднику Зиборову Виктору - {0} лет\n", ВозрастЗиборова);
// Строим LINQ-запрос к словарю сотрудников; выбираем тех,
// чей возраст больше 33 лет: var СписокВзрослыхСотрудников =
from Сотрудник in СловарьСотрудников
where Сотрудник.Value.Возраст >= 33
orderby Сотрудник.Value.Имя
select new
{
Сотрудник.Key, Сотрудник.Value.Возраст,
ЛетИлиГода = Сотрудник.Value.Возраст - 10F *
Math.Truncate(Сотрудник.Value.Возраст / 10F) >= 5
};
// Вывод результата запроса на консоль:
Console.WriteLine("Список сотрудников, старше 33 лет:");
foreach (var x in СписокВзрослыхСотрудников)
Console.WriteLine("{0}, возраст - {1} {2} ", x.Key, x.Возраст, х.ЛетИлиГода ? "лет" : "года");
Console.ReadKey();
}
}
}
Представленный текст программы очевиден. Вначале задаем массив сотрудников учреждения, в этом массиве всего 6 элементов. В комментарии показано, как можно организовать LINQ-запрос к заданному массиву. Далее массив конвертируем в словарь сотрудников, задавая в качестве ключа имя сотрудника. Затем организуем LINQ-запрос к словарю Dictionary, выбираем в новую коллекцию (список тех, чей возраст превышает 33 года. Учитываем, что при выводе на консоль списка выбранных сотрудников мы говорим "47 лет", но "34 года". То есть если из возрас. та вычесть число, кратное 10, то при остатке меньше 5 говорят, например, "34 года", а при остатке больше или равном 5 говорят "47 лет". Число, кратное 10, мы вычисляем, используя функцию Math.Truncate, которая возвращает целую часть числа, поданную на ее вход. В этом алгоритме мы использовали булеву переменную ЛетИлиГода, которая определяет (по принципу "да" или "нет") следует писать "лет" или "года".
Результат работы программы показан на рис. 11.4.
Рис. 11.4. Запрос к словарю данных на "взрослых" сотрудников
Убедиться в работоспособности программы можно, открыв решение LinqDictionary.sln папки LinqDictionary.
Пример 79. Создание XML-документа методами классов пространства имен System.Xml.Linq
Кроме пространства имен System.Xml, содержащего классы для обработк XML-документов, в Visual С#2010 имеем пространство имен System.Xml.Linq, содержащее классы, которые позволяют легко и эффективно изменять документы XML, а также организовывать LINQ-запросы. В данном примере оформим сведения о наших повседневных телефонных контактах в XML-документ. Этот документ будет иметь интуитивно понятную структуру: имя контакта, домашний и мольный телефоны. Создав такой XML-документ и получив соответствующий XML -файл, его очень удобно просмотреть в MS Excel в виде таблицы, содержащей три столбца: имя контакта, домашний телефон и мобильный. Попутно обсудим структуру XML-документа.
Итак, запустим среду Visual Studio 2010, выберем проект шаблона Console Арplication, укажем имя Name — LinqСоздатьXML-документ. Затем на вкладке программного кода введем текст, представленный в листинге 11.5.
Листинг 11.5. Создание