Высокоуровневые методы информатики и программирования Лекция 15 Коллекции Коллекции Коллекции – классы, объекты которых могут хранить ссылки на объекты других классов (контейнеры) Куча Коллекция Интерфейсы для работы с коллекциями Интерфейсы классов коллекций • IEnumerable - Составляет список объектов классов коллекций с помощью оператора foreach • IComparer - Сравнивает два объекта классов коллекций при их сортировке; • ICollection - Реализуется всеми классами коллекций для обеспечения доступа к методу СоруТо(), GetEnumerator() и свойство Count; • IList - Используется объектами классов коллекций, индексируемыми как массив. • IDictionary - Используется классами коллекций, осуществляющими доступ по ключу или значению, таких как Hashtable и SortedList. • IDictionaryEnumerator - Позволяет просмотреть (с помощью оператора foreach) объекты классов коллекций, поддерживающих интерфейс IDictionary Интерфейс IEnumerable interface IEnumerable { IEnumerator GetEnumerator(); } interface IEnumerator { public bool MoveNext(); // i++ public void Reset(); // i=0; public оbject Current {get;}); //property } Коллекции • System.Array - массивы – простейший тип коллекций – фиксированный размер – однотипные объекты • System.Collections. – ArrayList – неограниченный список элементов. – Queue – порядок элементов FIFO – Stack – порядок элементов LIFO – Hashtable – словарь (ключ - значение), оптимизирован для быстрого поиска значний. Коллекции в .NET • System.Collections – Нетипизированные коллекции – Специализированные коллекции • System.Collections.Generic – Шаблонные коллекции Основные элементы интерфейса ICollection Элемент Описание Count свойство – количество объектов в коллекции CopyTo() метод копирования элементов коллекции в массив типа Array, начинас с заданного индекса массива GetEnumerator() получение объекта, поддерживающего интерфейс IEnumerable), который позволяет просматривать всю коллекцию (для foreach) Основные элементы интерфейса IList Элемент Add() метод добавления объекта к коллекции Clear() удаление всех объектов из коллекции Contains() проверка на наличие в коллекции объекта (true/false) IndexOf() определение индекса для заданного объекта Insert() вставка объекта в место заданное индексом Remove() удаление первого встреченного экземпляра указанного объекта удаление всех объектов, начиная с заданного индекса RemoveAt() [index] Описание индексатор, который позволяет получить или задать объекты по заданному индексу. Основные элементы интерфейса IDictionary • Описывает не обобщенную коллекцию пар (ключ, значение) • Основные методы: – Add() – добавляет элемент с заданным ключем и значением; – Clear() – удаляет все элементы из словаря; – Contains () – проверяетсодержит ли словарь заданный элемент; – CopyTo() – копирует элементы ICollection в массив начиная с заданного индекса массива (наследуется от ICollection); – GetEnumerator() – перегруженный метод для получения объекта Enumerator. – Remove () – удаление всех элементов с заданным ключем из объекта IDictionary. Типы нетипизированных коллекций • ArrayList – простая коллекция (наследуется от интерфейса IList), которая может хранить объекты любого типа. Экземпляры ArrayList могут хранить произвольное количество объектов, при необходимости, они увеличивают объем используемой памяти. • Queue – коллекция, которая поддерживает следующий порядок работы с объектами: «первым пришел, первым вышел» (first-in, first-out – FIFO). Можно использовать Queue на сервере обработки сообщений, для временного хранения сообщений перед обработкой, или для хранения информации о клиентах, которые должны обрабатываться в порядке «Первым – пришел, первым – ушел». • Stack – коллекция, которая поддерживает следующий порядок работы с объектами: «Последним пришел – первым ушел» (lastin, first-out – LIFO). Можно использовать Stack для хранения наиболее новых изменений, чтобы можно было их отменить. Класс ArrayList • Реализует интерфейсы IList, ICollection, IEnumerable, ICloneable, используя массив, размер которого динамически меняется по необходимости. ArrayList arl = new ArrayList( ); • Свойства – Сount – количество элементов – Capacity – текущий объем списка – Item – получение элемента по индексу (indexer [ i ] – операция) • Методы – – – – Add( ) – добавить объект Clear( ) – очистить Sort( ) – сортировать … Пример работы ArrayList al = new ArrayList(); al.Add("Привет"); al.Add("Мир"); al.Add(5); al.Add(new FileStream("delemete", FileMode.Create)); Console.WriteLine("Коллекция содержит " + al.Count + " элемента:"); foreach (object s in al) Console.Write(s.ToString() + " "); • Результат Коллекция содержит 4 элемента: Привет Мир 5 System.IO.FileStream ArrayList al = new ArrayList(); ArrayList al = new ArrayList() {"Привет", "Мир", "это", "проверка"}; al.Remove("это"); al.Insert(1, "Наш"); al.Sort(); foreach (object s in al) Console.Write(s.ToString() + " "); • Результатом работы будет следующая строка: Мир Наш Привет проверка Метод преобразования коллекции к типу OfType<T>() • В не типизированных коллекциях могут храниться данные любого типа. • Для применения LINQ нужно выбрать из них только те, которые имеют определенный тип (преобразовать в типизированную коллекцию) • Метод OfType<T>() выбирает из нетипизированной коллекции только объекты заданного типа и преобразует их к типу IEnumerable<TResult>. • Например: // Extract the ints from the ArrayList. ArrayList myStuff = new ArrayList(); myStuff.AddRange(new object[] { 10, 400, 8, false, new Car(), "string data" }); IEnumerable<int> myInts = myStuff.OfType<int>(); // Prints out 10, 400, and 8. foreach (int i in myInts) { Console.WriteLine("Int value: {0}", i); } Класс очередей (Queue) • Очередь (queue) - это класс коллекций, организованный по принципу FIFO (первым вошел - первым вышел). Классическая аналогия - очередь в кассу за билетами. Первый человек, стоящий в очереди, первый и выйдет из нее, когда купит билет. • Очередь удачно подходит для управления ограниченными ресурсами. Свойства и методы очереди • Свойство – Count - Открытое свойство, позволяющее узнать текущее количество элементов очереди • Методы – Enqueue() - Добавляет объект в конец объекта Queue – Dequeue() - Возвращает объект, стоящий в начале объекта Queue, и удаляет его из очереди – Peek() - Возвращает объект, стоящий в начале объекта Queue, не удаляя его – Contains () - Выясняет, находится ли данный элемент в объекте Queue – Clear() - Удаляет все элементы из объекта Queue Queue q = new Queue(); q.Enqueue("Привет"); q.Enqueue("мир"); q.Enqueue("просто тестирование"); Console.WriteLine("Использование Queue:"); for (int i = 1; i <= 3; i++) Console.WriteLine (q.Dequeue().ToString()); • Результат: Использование Queue: Привет мир просто тестирование Класс Stack (Стек) • это класс коллекции, организованный по принципу LIFO (последним вошел- первым вышел). • Аналогией может служить стопка подносов в столовой самообслуживания (или, например, столбик из монет). Поднос, положенный в стопку последним, будет взят оттуда первым. • Основными методами для работы со стеком являются Push ( ) (добавление элемента) и Рор() (удаление). • Кроме того, класс Stack предоставляет метод Peek(), аналогичный одноименному методу класса Queue. Свойства и методы стека • Свойство – int Count – количество элементов стека • Методы – void Push() – Помещает объект на вершину объекта Stack – object Pop() - Возвращает объект, находящийся на вершине объекта Stack, и удаляет его из стека – object Peek() – Возвращает объект, находящийся на вершине объекта Stack, не удаляя его – void Clear() – убрать все объекты – bool Contains(a) – проверка есть элемент Пример работы со стеком Stack s = new Stack(); s.Push("Привет"); s.Push("мир"); s.Push("просто тестирование"); Console.WriteLine("\nИспользование Stack:"); for (int i = 0; i < 3; i++) Console.WriteLine (s.Pop().ToString()); • Результат: Stack demonstration: просто тестирование мир Привет Словари • Классы словарей (dictionaries) задают соответствие между ключами (key) и значениями (value). Например, можно связать идентификатор сотрудника (например, табельный номер) с объектом класса, описывающего сотрудника номер. • Значение словаря можно найти по значению ключа: – значение = словарь [ключ]; Ключ Словарь Ссылка Куча Типы нетипизированных словарей • Классы словарей (dictionaries) задают соответствие между ключами (key) и значениями (value). Например, можно связать идентификатор сотрудника (например, табельный номер) с объектом класса, описывающего сотрудника номер. В FCL включены следующие основные классы словарей: • Hashtable – словарь (хешированная таблица) пар (имя, значение), которые могут быть получены по имени или индексу; • SortedList – словарь, который автоматически сортируется по ключу; • StringDictionary – словарь Hashtable в котором пары имя/значение могут быть только строками string. Отсортированный список SortedList • Поддерживает интерфейсы IDictionary, ICollection, IEnumerable, ICloneable • Представляет собой коллекцию пар (ключ, значение), которые сортируются по ключу и доступны – по ключу [ключ] и – индексу [i]. SortedList sl = new SortedList(); sl.Add("Stack", "Коллекция объектов типа LIFO."); sl.Add("Queue", "Коллекция объектов типа FIFO."); sl.Add("SortedList", "Коллекция пар ключ/значение."); foreach (DictionaryEntry de in sl) Console.WriteLine(de.Value); string s = (string)sl["Queue"]; // s = "Коллекция объектов типа FIFO.« Класс Hashtable (Хеш-таблица) • это словарь, оптимизированный для максимально быстрого получения информации. • Хранение пар (ключ, значение) организовано в соответствии с хэш кодом ключа. • В объекте Hashtable каждое значение хранится в блоках. Блоки пронумерованы, чем напоминают элементы массива. • Поскольку ключ может и не быть целым числом, нужен способ преобразования ключа (например строки “Иванов”) в номер блока. • Каждый ключ обязан предоставить метод GetHashCode(), выполняющий это действие. Хеш-код (продолжение) • Стандартная реализация метода GetHashCode() для строки сводится к тому, что Unicode-коды всех символов строки складываются, а затем с помощью деления по модулю получается значение от 0 до N, где N - количество блоков в хеш-таблице. Писать такой метод для типа string не надо, так как среда CLR предоставляет его по умолчанию. • Когда в объект Hashtable вставляются значения, он вызывает метод GetHashCode() для каждого указанного ключа. Метод возвращает целочисленное значение, идентифицирующее блок, в который помещено значение. • Не исключена ситуация, когда для нескольких ключей будет возвращен один номер блока. Это называется конфликтом (collision). Существует ряд способов разрешения конфликтов. Самым распространенным подходом, к тому же принятым в CLR, является ведение упорядоченного списка значений в каждом блоке. Свойства и методы Hashtable • Свойства – Count – текущее число элементов – [ ] – индексатор • Методы – Clear() - Удаляет все элементы из объекта Hashtable – Add(object k, object v) - Добавляет запись с указанной парой ключ/значение – Remove() - Удаляет запись с указанным ключом – ContainsKey () - проверить наличие заданного ключа. – ContainsValue () - проверить наличие заданного значения. Универсальные классы (Generic classes) Обобщения (generics) • Под обобщением (универсальностью, generality) понимается способность типа объявлять используемые им другие типы как параметры. • Класс с параметрами, задающими типы, называется обобщенным или универсальным классом (generic class). • Обобщенными могут быть: – – – – классы методы делегаты интерфейсы Обобщенные классы (Generic Classes) class MyClass<T1, ... Tn> {...} • Пример обобщенного класса: public class Point<T> { //координаты точки, тип которых задан параметром T x, y; // другие свойства и методы структуры ... } • При описании переменной данного типа нужно задать конкретный используемый тип. • Например: Point<int> pt; pt = new Point<int> (); Пример обобщенного метода: class Change { static public void Swap<T>(ref T x1, ref T x2) { T temp; temp = x1; x1 = x2; x2 = temp; } } Использование обобщенного метода public void TestSwap() { int x1 = 5, x2 = 7; Change.Swap<int>(ref x1, ref x2); erson pers1 = new Person("Савлов", 25, 1500); Person pers2 = new Person("Павлов", 35, 2100); Change.Swap<Person>(ref pers1, ref pers2); } Стандартные обобщенные делегаты • • • • • • • В библиотеке FCL описаны стандартные обобщенные делегаты, которые активно используются в методах классов библиотеки: System.Action() – принимает значение (или значения) и ничего не возвращает; public delegate void Action<T>( T obj ) System.Comparison() – принимает два параметра и возвращает целое значение (< 0: x < y; 0: x == y; > 0: x > y) public delegate int Comparison<T>( T x, T y ) System.Converter() – преобразование объекта из одного типа в другой public delegate TOutput Converter<TInput, Toutput> ( TInput input ) System.EventHandler – обработчик событий public delegate void EventHandler<TEventArgs> ( Object sender, TEventArgs e ) where TEventArgs : EventArgs System.Func() – принимает значение (или значения) и возвращает результат public delegate TResult Func<T, TResult>( T arg ) System.Predicate() – принимает значение и возвращает bool public delegate bool Predicate<T>( T obj ) Стандартные обобщенные интерфейсы • • • • • • ICollection<T> IComparer<T> IDictionary<TKey, TValue> IEnumerable<T> IEnumerator<T> IList<T> Стандартные пространства имен • • • • • System – содержит основные базовые классы; System.Collections – содержит интерфейсы и классы, которые описывают разные типы коллекций и словарей (не обобщенные). System.Collections.Generic содержит интерфейсы и классы, которые описывают обобщенные коллекции и словари, которые позволяют пользователям создавать строго типизированные коллекции, предоставляющие лучшую безопасность работы с типами и лучшую производительность, чем не обобщенные коллекции; System.Linq содержит классы и интерфейсы, которые поддерживают интегрированный в язык C# язык запросов - Language-Integrated Query (LINQ). System.Text содержит классы представляющие методы кодировки символов ASCII, Unicode, UTF-7 и UTF-8; абстрактные базовые классы для конвертирования наборов символов в набор байтов; и вспомогательный класс для манипулирования и форматирования String объектов без создания промежуточных экземпляров типа String. Обобщенные коллекции из System.Collections.Generic • List<тип> - список элементов переменного размера; • Queue <тип> – порядок элементов FIFO; • Stack <тип> – порядок элементов LIFO; • LinkedList<тип> - двухсвязный список; • Dictionary<TKey, TValue> (dictionary – коллекция, которая ассоциирует ключ (key) со значением (value)) Соответствие между обобщенными классами и их обычными двойниками Универсальный класс Обычный класс List<T> ArrayList Queue<T> Queue Stack<T> Stack SortedDictionary<K,T> SortedList Dictionary<K,T> LinkedList<T> HashTable нет Пример использования Stack<Point> sp; sp = new Stack<Point>(); sp.Push(p); Point[ ] pa; pa = sp.ToArray(); public class Person : IComparable { string firstName, lastName; public int CompareTo(object obj) { Person otherPerson = (Person)obj; if (this.lastName != otherPerson.lastName) return this.lastName.CompareTo(otherPerson.lastName); else return this.firstName.CompareTo (otherPerson.firstName); } public Person(string _firstName, string _lastName){ firstName = _firstName; lastName = _lastName; } override public string ToString() { return firstName + " " + lastName; } } List<Person> group = new List<Person>(); group.Add(new Person("Григорий", "Дубина")); group.Add(new Person("Иван", "Ходырев")); group.Add(new Person("Александр", "Луценко")); group.Sort(); foreach (Person p in group) Console.Write(p.ToString() + ";"); SortedList<string, int> sl = new SortedList<string, int>(); sl.Add("One", 1); sl.Add("Two", 2); sl.Add("Three", 3); foreach (int i in sl.Values) Console.Write(i.ToString() + " "); int n = sl[“Two”]; // значение 2 • Результат выполнения примера: 132 Словарь Dictionary <TKey, Tvalue> • Словарь (dictionary) - это класс коллекции, связывающий ключ со значением. • По такому же принципу построены толковые словари, например словарь Вебстера связывает слово (ключ) с его толкованием (значение). Свойства и методы IDictionary • Свойство – Item – получить или записать элемент – Keys – получить ICollection всех ключей – Values - получить ICollection всех значений • Методы – Add() – добавить ключ и значение к словарю; – Clear() – удалить все ключи и значения из словаря; – Remove () – удалить значение с указанным ключем; – bool ContainsKey(key) – определить есть ли в словаре указанный ключ; – bool ContainsValue(value) - определить есть ли в словаре указанное значение; – bool TryGetValue(key, out value) - получить значение связанное с заданным ключом.