Пример разработки приложения демонстрации работы списков и ассоциативных массивов. Классы Dictionary, List, StreamReader
В данной теме приведен пример разработки приложения типа Windows Forms Application, которое демонстрирует использование списков (класс List) и ассоциативных массивов (класс Dictionary).
Приложение реализует лабораторную работу одного из учебных заведений.
Используя данный пример Вы получите опыт работы с классами Dictionary<TKey,TValue> и List<T>, которые относятся к обобщенным коллекциям.
При разработке приложения реализованы следующие задачи:
- чтение данных из файла и отображение их в элементе управления типа ListBox;
- демонстрация использования класса StreamReader из модуля System.IO для чтения данных из файла;
- демонстрация работы класса Dictionary<TKey, TValue> для организации коллекции. Класс сохраняет пары «ключ-значение»;
- демонстрация работы класса List<T> для организации динамического массива или списка.
Содержание
- Условие задачи
- Выполнение
- 1. Запустить MS Visual Studio. Создать проект по шаблону Windows Forms Application
- 2. Создание формы приложения.
- 3. Настройка свойств элементов управления.
- 4. Организация данных в виде структур.
- 5. Классы Dictionary<Key,Value> и List<T>. Описание основных структур данных.
- 6. Подключение пространства имен System.IO. Класс StreamReader.
- 7. Программирование методов чтения данных из файлов «Flight.txt» и «Tickets.txt».
- 8. Изменение кода конструктора формы Form1().
- 9. Программирование события клика на кнопке «Вычислить».
- 10. Запуск приложения на выполнение.
Поиск на других ресурсах:
Условие задачи
Реализовать приложение типа Windows Forms Application с использованием списков и ассоциативных массивов.
Дано два текстовых файла: «Flight.txt» и «Tickets.txt«.
Файлы содержат неограниченное количество строк. Каждая строка файла содержит данные, которые разделены символом ‘ , ‘ (запятая).
Одна строка файла «Flight.txt» имеет следующую структуру:
- номер рейса (целое число);
- пункт отправки (строка символов);
- время вылета, часа (целое число);
- общее количество мест (целое число).
Одна строка файла «Tickets.txt» имеет следующую структуру:
- номер билета (целое число);
- номер рейса (целое число);
- место (целое число);
- дата вылета (строка символов);
- пункт назначения (строка символов);
- дата прибытия (строка символов);
- время прибытия (целое число);
- цена (число с плавающей запятой);
- время продажи билета (строка символов).
В программе нужно решить следующие задачи:
1. Прочитать данные из файла «Flight.txt» и выполнить над ними следующие операции:
- отобразить их на Windows-форме в элементе управления типа ListBox;
- организовать данные в коллекцию (класс Dictionary<TKey, TValue>).
2. Прочитать данные из файла «Tickets.txt» и выполнить над ними следующие операции:
- отобразить их на Windows-форме в элементе управления типа ListBox;
- организовать данные в динамический массив (класс List<T>).
3. Вывести на форму рейсы с максимальной продолжительностью полета. Вычисление выполнить с использованием классов Dictionary<TKey, TValue> и List<T>.
4. Вывести на форму число пассажиров, которые ждут отправления в введенный момент времени. Вычисление выполнить с использованием классов Dictionary<TKey, TValue> и List<T>.
Пример содержимого файла Flight.txt:
1,Kiev,18,120 2,Kiev ,19,100 3,Kiev,20,90 4,Kiev,22,150
Пример файла «Tickets.txt«:
1,1,1,05.10.2016,California,06.10.2016,21,500,14:10 2,1,1,05.10.2016,California,06.10.2016,21,500,14:30 3,2,1,05.10.2016,Croatia,06.10.2016,22,245,14:45 4,2,2,05.10.2016,Croatia,06.10.2016,22,245,14:50 5,2,3,05.10.2016,Croatia,06.10.2016,22,245,14:51 6,3,1,05.10.2016,Amsterdam,06.10.2016,23,400,14:55 7,3,3,05.10.2016,Amsterdam,06.10.2016,23,400,15:10 8,3,7,05.10.2016,Amsterdam,06.10.2016,23,400,15:25 9,4,1,05.10.2016,Moscow,06.10.2016,24,350,15:27 10,4,10,05.10.2016,Moscow,06.10.2016,24,350,16:08
⇑
Выполнение
1. Запустить MS Visual Studio.
Создать проект по шаблону C# как Windows Forms Application. Пример создания такого проекта подробно описывается здесь.
⇑
2. Создание формы приложения.
Разместить на форме следующие элементы управления (рисунок 1):
- элемент управления типа ListBox для отображения данных из файла «Flights.txt«. Автоматически создается объект с именем listBox1;
- элемент управления типа ListBox для отображения данных из файла «Tickets.txt«. Автоматически создается объект с именем listBox2;
- элементы управления типа Label для отображения информационных сообщений. Создаются объекты с именами label1, label2, label3, label4, label5;
- элемент управления типа TextBox который представляет строку ввода данных (время отправления). Создается объект с именем textBox1;
- элемент управления типа Button (кнопка «Вычислить«). Создается объект с именем button1;
- элемент управления типа ListBox (список рейсов с максимальной продолжительностью полетов). Создается объект с именем listBox3.
Скорректировать размеры и позиции элементов управления так как показано на рисунке 1.
Рис. 1. Форма приложения после размещения элементов управления
⇑
3. Настройка свойств элементов управления.
Настройка свойств элементов управления осуществляется с помощью окна «Properties» системы Microsoft Visual Studio 2010.
Настроить следующие свойства элементов управления:
- в элементе управления label1 свойство Text = «Файл Flight.txt»;
- в элементе управления label2 свойство Text = «Файл Tickets.txt»;
- в элементе управления label3 свойство Text = «Время отправления»;
- в элементе управления textBox1 свойство Text = «»;
- в элементе управления label4 свойство Text = «Число пассажиров, которые ждут отправления: «;
- в элементе управления button1 свойство Text = «Вычислить»;
- в элементе управления label5 свойство Text = «Рейсы максимальной продолжительностью полета:».
После настройки свойств и корректирования позиций и размеров элементов управления форма приложения будет иметь вид как показано на рисунке 2.
Рис. 2. Форма приложения после настройки элементов управления
⇑
4. Организация данных в виде структур.
Данные, которые размещаются в одной строке того или иного файла целесообразно представить в виде структуры. Это осуществляется с целью повышения эффективности работы программы. Так как, в отличие от класса, который есть ссылкой, структуры в C# реализованы как типы-значения. В сравнении со структурами, при доступе к объектам класса по ссылке, увеличивается количество выделенных ресурсов и оперативной памяти.
Представим данные одной строки файла «Flight.txt» в виде структуры Flight:
// Структура "Авиарейсы" public struct Flight { public int num_r; // номер рейса public string punkt_vd; // пункт отправления public int time_v; // время вылета public int n_places; // общее количество мест }
По тому же принципу представляются данные одной строки файла «Tickets.txt» в структуре Tickets:
// Структура "Билеты" public struct Tickets { public int num_t; // номер билета public int num_r; // номер рейса public int place; // место public string date_v; // дата вылета public string punkt_pr; //пункт назначения public string data_pr; // дата прибытия public int time_pr; // время прибытия public double price; // цена public string time_prod; // время продажи билета }
Фрагмент листинга файла «Form1.cs» после ввода структур имеет следующий вид:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace Kontrolna_UZHNU_1 { public partial class Form1 : Form { // Структура "Авиарейсы" public struct Flight { public int num_r; // номер рейса public string punkt_vd; // пункт отправления public int time_v; // время вылета public int n_places; // общее количество мест } public struct Tickets { public int num_t; // номер билета public int num_r; // номер рейса public int place; // место public string date_v; // дата вылета public string punkt_pr; //пункт назначения public string data_pr; // дата прибытия public int time_pr; // время прибытия public double price; // цена public string time_prod; // время продажи билета } public Form1() { InitializeComponent(); } } }
⇑
5. Классы Dictionary<Key,Value> и List<T>. Описание основных структур данных.
В соответствии с условием задачи, данные, которые размещены в файлах «Flight.txt» и «Tickets.txt«, формируются в коллекции.
Коллекция типа «словарь» (Dictionary) представляется в виде: «ключ-значение». Причем значение ключа есть уникальным (не может повторяться).
Для структуры Flight целесообразно сформировать данные в виде словаря или ассоциированного массива. Это связано с тем, что номер рейса в списке рейсов есть уникальным (не может повторяться).
В C# для представления коллекции типа «словарь» (ассоциированный массив) реализовано два базовых класса:
- класс HashTable – принадлежит к необобщенным коллекциям;
- класс Dictionary – принадлежит к обобщенным коллекциям.
В соответствии с условием задачи, нужно использовать класс Dictionary.
Для представления ассоциированного массива в текст класса формы нужно ввести объект с именем avia, что есть типа Dictionary<int, Flight>:
// Ассоциированный массив структур "Авиарейсы" Dictionary<int, Flight> avia = new Dictionary<int, Flight>();
В этом описании тип int есть номером рейса, а тип Flight есть структурой, которая соответствует этому рейсу.
Для разных рейсов номер билета может повторяться. Поэтому, удобно реализовать билеты в виде обобщенного динамического массива типа List<T>. Вместо типа <T> подставляется структура Tickets – в итоге получается List<Tickets>.
Ввести объект с именем tickets:
// Динамический массив (список) структур "Билеты" List<Tickets> tickets = new List<Tickets>();
⇑
6. Подключение пространства имен System.IO. Класс StreamReader.
В соответствии с условием задачи, в программе осуществляется чтение из файла. Библиотека классов .NET Framework представляет множество средств для организации взаимодействия программы с файлами (открытие файла, чтение файла и т.д.).
В данной работе использованы возможности класса StreamReader. Этот класс описывается в просторные имен System.IO. Итак, в начале файла «Form1.cs» нужно ввести строку:
using System.IO;
Класс StreamReader предназначен для ввода символов из байтового потока. Для вывода символов в байтовый поток используется класс StreamWriter.
В классе StreamReader есть метод ReadLine(), читающий текстовую строку из файла. Метод ReadLine() возвращает строку типа string. Этот метод будет использован при чтении файла в данной задаче.
⇑
7. Программирование методов чтения данных из файлов «Flight.txt» и «Tickets.txt«.
Прочитанные из файлов «Flight.txt» и «Tickets.txt» данные отображаются в элементах управления listBox1 и listBox2. Для отображения данных нужно создать два метода.
Первый метод Read_Avia() выполняет следующие операции:
- читает список авиарейсов из файла «Flight.txt«;
- формирует ассоциированный массив avia типа Dictionary<int, Flight>;
- формирует список авиарейсов в listBox1 для его отображения на форме.
Второй метод Read_Tickets() выполняет следующие операции:
- читает перечень купленных билетов из файла «Tickets.txt«;
- формирует динамический массив tickets типа List<Tickets>;
- выводит содержимое файла «Tickets.txt» в listBox2.
Листинг методов Read_Avia() и Read_Tickets() следующий:
public void Read_Avia() { StreamReader sr = new StreamReader("Flight.txt", Encoding.Default); string s = ""; string[] fields; Flight sa; // дополнительная переменная - структура типа Flight // Основной цикл. // В цикле: // 1. Читаются данные из файла "Flight.txt" // 2. Формируется словарь avia типа Dictionary<int, Flight> while (s != null) { s = sr.ReadLine(); // прочитать строку из файла if (s != null) { fields = s.Split(','); // формирование структуры sa типа struct Flight sa.num_r = Convert.ToInt32(fields[0]); sa.punkt_vd = fields[1]; sa.time_v = Convert.ToInt32(fields[2]); sa.n_places = Convert.ToInt32(fields[3]); // добавляем пару <num_r, sa> в словарь avia // ключом к структуре есть номер рейса num_r avia.Add(sa.num_r, sa); // добавить строку s в listBox1 listBox1.Items.Add(s); } } } public void Read_Tickets() { StreamReader sr = new StreamReader("Tickets.txt", Encoding.Default); string s; string[] fields; // массив строк-полей структуры Tickets Tickets tk; // вспомогательная переменная-структура s = sr.ReadLine(); // Основной цикл. // В цикле: // 1. Читаются данные из файла "Tickets.txt" // 2. Формируется список tickets типа List<Tickets> // используем цикл do...while() do { // разбить строку s на части по признаку символа ',' fields = s.Split(','); // заполнить структуру tk tk.num_t = Convert.ToInt32(fields[0]); tk.num_r = Convert.ToInt32(fields[1]); tk.place = Convert.ToInt32(fields[2]); tk.date_v = fields[3]; tk.punkt_pr = fields[4]; tk.data_pr = fields[5]; tk.time_pr = Convert.ToInt32(fields[6]); tk.price = Convert.ToDouble(fields[7]); tk.time_prod = fields[8]; // добавить заполненную структуру в список tickets tickets.Add(tk); listBox2.Items.Add(s); s = sr.ReadLine(); } while (s != null); }
Объясним некоторые фрагменты кода в методах Read_Avia() и Read_Tickets().
Чтение файла осуществляется с помощью класса StreamReader, который предназначен для ввода символов из байтового потока. Открытие файлов реализуется в конструкторе класса StreamReader:
StreamReader sr = new StreamReader("Flight.txt", Encoding.Default); StreamReader sr = new StreamReader("Tickets.txt", Encoding.Default);
Чтение строки из файла осуществляется методом ReadLine() класса StreamReader. Если достигнут конец файла, то метод возвращает null.
С помощью строки
fields = s.Split(',');
происходит разделение строки на составные части. Разделитель между составными частями – это символ ‘ , ‘.
Строка
avia.Add(sa.num_r, sa);
добавляет в коллекцию avia типа Dictionary<int, Flight> номер рейса и заполненную структуру sa.
Строка
tickets.Add(tk);
добавляет в коллекцию tk типа List<Tickets> структуру tk.
⇑
8. Изменение кода конструктора формы Form1().
Методы Read_Avia() и Read_Tickets() размещаются в конструкторе формы Form1().
Листинг конструктора формы Form1() следующий:
public Form1()
{
InitializeComponent();
Read_Avia();
Read_Tickets();
}
⇑
9. Программирование события клика на кнопке «Вычислить«.
Листинг обработчика события клика на кнопке «Вычислить» имеет вид:
private void button1_Click(object sender, EventArgs e) { // Расчет // 1. Рейсы с максимальной продолжительностью полета int i, j; int max, tmp; bool f_first = true; max = 0; foreach (var a in avia) { foreach (var t in tickets) if (a.Value.num_r == t.num_r) { if (f_first) { max = t.time_pr - a.Value.time_v; f_first = false; } else { tmp = t.time_pr - a.Value.time_v; if (max < tmp) max = tmp; } } } // на выходе получаем максимальную длительность полета в переменной max // формирование списка рейсов с максимальной продолжительностью полета listBox3.Items.Clear(); foreach (var a in avia) { foreach (var t in tickets) if (a.Value.num_r == t.num_r) { tmp = t.time_pr - a.Value.time_v; if (tmp == max) { string s; s = a.Value.num_r.ToString() + ", " + a.Value.punkt_vd + ", " + a.Value.time_v.ToString() + ", " + a.Value.n_places.ToString() + " - " + t.num_t.ToString() + ", " + t.punkt_pr + ", " + t.time_pr.ToString() + ", " + t.place.ToString(); listBox3.Items.Add(s); } } } label4.Text = "Рейсы с максимальной продолжительностью полета: " + max.ToString(); // 2. Число пассажиров, которые ждут отправления в введенный момент времени int tm, k; tm = Int32.Parse(textBox1.Text); // получить время k = 0; // число пассажиров foreach (var a in avia) { foreach (var t in tickets) if ((a.Value.num_r == t.num_r)&&(tm==a.Value.time_v)) k++; } label5.Text = "Число пассажиров, которые ждут отправления: " + k.ToString(); }
В вышеприведенном листинге следует отметить. При просмотре коллекций используется оператор foreach (и только foreach). Оператор foreach служит для циклического обращения к элементам коллекции, которая представляет собой группу объектов. Использование других операторов цикла приводит к ошибке.
Список рейсов с максимальной продолжительностью полета выводится в элемент управления listBox3.
⇑
10. Запуск приложения на выполнение.
Результат работы приложения изображен на рисунке 3.
Рис. 3. Результат работы приложения
⇑