Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Универсальные коллекции языка С#. Учебное пособие
.pdf
Демонстрируется использование метода TryGetValue как более эффективный способ получения значений, если в программе часто используются значения ключей, которые не находятся в сортированном
списке, а также показано, как использовать метод ContainsKey для
проверки наличия ключа перед вызовом метода Add.
Показано, как перечислить ключи и значения в сортированном
списке, а также как перечислить только
ключи и значения с помощью
свойства Keys и свойства Values. Демонстрируется использование метода Remove для удаления элемента по ключу.
usingSystem;
usingSystem.Collections.Generic;
namespaceПример_1
{
classProgram
{
//Методдлявыводасловарянаэкран.
staticvoidPrint<TKey,TValue>(inSortedList<TKey,TValue>cnt,stringheader)
{
Console.WriteLine(header);
foreach(varpareincnt)
{
Console.WriteLine($"{pare.Key,15}{pare.Value,10}");
}
Console.WriteLine();
}
staticvoidMain(string[]args)
{
//Городамилионники.Населениевтысячахчеловек.
//Создаетновыйсортированныйсписокцелыхчисел,
SortedList<string,int>cyties=newSortedList<string,int>()
{
{"Челябинск",1196},
{"Омск",1154},
{"Самара",1156},
{"Ростов‐на‐Дону",1137},
{"Уфа",1128},
};
состроковымиключами.
51

Print(cyties,"Городамилионники:");
//Добавляемнесколькоэлементовксловарю.Внихнедолжнобыть
//дубликатовключейсловаря,
//нонекоторыезначениямогутдублироваться.
cyties.Add("Красноярск",1093);
cyties.Add("Пермь",1055);
//МетодAddmethodвыбрасываетисключение,
//еслиновыйключужеестьвсловаре.
Print(cyties,"Городамилионникипоследобавления:");
try
{
cyties.Add("Самара",1156);
}
catch(ArgumentException)
{
Console.WriteLine("Элементсключом=\"Самара\"Ужесуществует.");
}
//СвойствоItemявляетсядругимименемдляиндексатора
//можноопускатьегоимяприобращениикэлементам.
Console.WriteLine("Дляключа=\"Омск\",value={0}.",
cyties["Омск"]);
//Индексможноиспользовать,чтобыизменитьзначениесвязанного
//снимключа.
cyties["Пермь"]=1057;
Console.WriteLine("Дляключа=\"Пермь\",value={0}.",
cyties["Пермь"]);
//Еслиключнесуществует,присваиваниеиндексаторудляэтогоключа
//добавляетновуюпаруключ/значение(key/value).
cyties["Воронеж"]=1058;
//Индексаторвыбрасываетисключение,еслизапрашиваемогоключанет
//всловаре.
try
{
Console.WriteLine("Forkey=\"tif\",value={0}.",
cyties["Краснодар"]);
}
catch(KeyNotFoundException)
{
Console.WriteLine("Ключ=\"Краснодар\"несуществует.");
}
//Когдапрограммачастодолжназапрашиватьключи,которыхможет
//неоказатьсявсловаре,
//TryGetValueможетстатьболееэффективнымпутемизвлекатьзначения.
,такчто
52

intvalue;
if(cyties.TryGetValue("",outvalue))
{
Console.WriteLine("Дляключа=\"Челябинск\",value={0}.",value);
}
else
{
Console.WriteLine("Ключ=\"Челябинск\"Ненайден.");
}
//ContainsKeyможноиспользоватьдляпроверкиключейпередихвставкой.
if(!cyties.ContainsKey("ht"))
{
cyties.Add("Волгоград",1008);
Console.WriteLine("Значениедобавленодляключа=\"Волгоград\":{0}",
cyties["Волгоград"]);
}
//Когдавыиспользуете
//элементыизвлекаютсякакKeyValuePairобъекты.
Console.WriteLine();
foreach(KeyValuePair<string,int>kvpincyties)
{
Console.WriteLine("Ключ={0,15},Значение={1,10}",
kvp.Key,kvp.Value);
}
//Чтобыполучитьтолькозначения,используйтесвойствоValues.
Console.WriteLine();
foreach(intvalincyties.Values)
{
Console.WriteLine("Значение={0}",val);
}
//Чтобыполучитьтолькоключи,используйтесвойствоKeys.
Console.WriteLine();
foreach(stringkey
{
Console.WriteLine("Ключ={0}",key);
}
//ТспользуйтеметодRemoveчтобыудалитьпаруключ/значение(key/value).
Console.WriteLine("\nRemove(\"Челябинск\")");
cyties.Remove("Челябинск");
if(!cyties.ContainsKey("Челябинск"))
{
Console.WriteLine("Ключ\"Челябинск\"ненайден.");
}
foreachперебораэлементовсловаря,
incyties.Keys)
53

}
}
}
Результатработыпримера:
Городамилионники:
Омск1154
Ростов‐на‐Дону1137
Самара1156
Уфа1128
Челябинск1196
Городамилионникипоследобавления:
Красноярск1093
Омск1154
Пермь1055
Ростов‐на‐Дону1137
Самара1156
Уфа1128
Челябинск1196
Элементсключом="Самара"Ужесуществует.
Дляключа="Омск",value=1154.
Дляключа="Пермь",value=1057.
Ключ="Краснодар"несуществует.
Ключ=
"Челябинск"Ненайден.
Значениедобавленодляключа="Волгоград":1008
Ключ=Волгоград,Значение=1008
Ключ=Воронеж,Значение=1058
Ключ=Красноярск,Значение=1093
Ключ=Омск,Значение=1154
Ключ=Пермь,Значение=1057
Ключ=Ростов‐на‐Дону,Значение=1137
Ключ=Самара,Значение=1156
Ключ=Уфа,Значение=1128
Ключ=Челябинск,Значение=1196
Значение=1008
Значение=1058
Значение=1093
Значение=1154
Значение=1057
Значение=1137
Значение=1156
54

Значение=1128
Значение=1196
Ключ=Волгоград
Ключ=Воронеж
Ключ=Красноярск
Ключ=Омск
Ключ=Пермь
Ключ=Ростов‐на‐Дону
Ключ=Самара
Ключ=Уфа
Ключ=Челябинск
Remove("Челябинск")
Ключ"Челябинск"ненайден.
КОЛЛЕКЦИЯ LINKEDLIST<T> – ДВУСВЯЗНЫЙ СПИСОК
Объект класса LinkedList<T> представляет собой двусвязный список, в котором каждый элемент ссылается на следующий и предыдущий, как показано на рисунке.
Следующий
Значение
Предыдущий
Следующий
Значение
Предыдущий
Следующий
Значение
Предыдущий
Преимущество двусвязного списка проявляется в том, что операция вставки элемента в середину выполняется очень быстро. При этом
только ссылки Next (следующий) предыдущего элемента и Previous
(предыдущий) следующего элемента должны быть изменены так, чтобы указывать на вставляемый элемент. Этим он отличается от коллекции List<T>, в которой при вставке нового элемента
все последующие
должны быть сдвинуты.
Недостаток двусвязного списка в том, что элементы двусвязных
списков доступны лишь друг за другом. Поэтому для нахождения элемента, находящегося в середине или конце списка, требуется довольно
55

много времени. В двусвязном списке информация пользователя хранится в узлах списка – объектах класса LinkedList<T> вместе со служебной информацией о следующем и предыдущем узле списка. Поэтому LinkedList<T> является двусвязным списком узлов типа
LinkedListNode<T>.
С помощью объектов класса LinkedListNode<T> появляется возможность обратиться к предыдущему и последующему элементу списка. Класс LinkedListNode<T> определяет свойства List, Next, Previous
и Value. Свойство List возвращает объект LinkedList<T>, с которым
узел ассоциирован. Свойства Next и Previous предназначены для итераций по списку, для доступа к следующему и предыдущему элементу.
Свойство Value типа T возвращает элемент, ассоциированный с узлом.
Класс LinkedList<T> определяет свойства для доступа к первому
(First) и последнему (Last) узлу в списке, методы для вставки элементов в определенные позиции: AddAfter() –
вставляет после заданного
узла, AddBefore() – вставляет перед заданным узлом, AddFirst() –
вставляет узел в начало, AddLast() – вставляет узел в конец; для удаления элементов из заданных позиций: Remove() – удаляет первое вхождение заданного значения, RemoveFirst() – удаляет первый узел,
RemoveLast() – удаляет последний узел; для нахождения элементов,
начиная поиск либо с начала списка Find() – находит первое вхождение заданного значения,
либо с конца списка FindLast() – находит по-
следнее вхождение заданного значения.
В классе LinkedList<T> реализуются интерфейсы ICollection, ICol-
lection<T>, IEnumerable, IEnumerable<T>, ISerializable и IDeserializationCallback (см. раздел Интерфейсы). В двух последних интерфейсах
поддерживается сериализация списка. В классе LinkedList<T> определяются два приведенных ниже открытых конструктора и свойства.
Конструкторы Назначение
LinkedList<T>() Инициализирует новый экземпляр пустого
класса LinkedList<T>
LinkedList<T>(IEnumerable<T>) Инициализирует новый экземпляр класса
LinkedList<T>, содержащий элементы, скопированные из указанного класса IEnumerable, и обладающий емкостью, достаточной
для того, чтобы вместить количество скопированных элементов.
56

Свойства Назначение
Count Обеспечивает доступ к числу узлов, которое в действительности
хранится в LinkedList<T>
First Обеспечивает доступ к первому узелу объекта LinkedList<T>
Last Обеспечивает доступ к последнему узелу объекта LinkedList<T>
Коллекция LinkedList<T> представляет отдельные узлы типа
LinkedListNode<T>, поэтому операции вставки и удаления являются
операциями с временной сложностью O(1).
Можно удалить узлы и повторно вставить их либо в тот же список,
либо в другой список, что приведет к тому, что в куче не будут выделены дополнительные объекты. Так как список хранит внутреннее ко
-
личество узлов, получение этого значения через свойство Count является операцией O(1).
Списки, содержащие ссылочные типы, работают лучше, когда узел
и его значение создаются одновременно. LinkedList<T> принимает null
как допустимое свойство Value для ссылочных типов и допускает дублирование значений. Если список пуст, свойства First и Last содержат
null.
В следующем примере создается двусвязный список LinkedList<
City>
и инициализируется с помощью конструктора без параметров.
В список добавляются объекты класса City методами Add, AddLast,
AddFirst, затем в него добавляются два объекта с помощью методов
AddBefore, AddAfter, и элементы списка выводятся на консоль. Выво-
дится число элементов в списке и максимальный элемент. Затем выводятся элементы списка, отфильтрованные методом Where с предикатом, заданным лямбда-выражением
(см. раздел Лямбда-выражения).
С помощью метода Reverse создается объект запроса, с помощью которого можно получить доступ к элементам списка в обратном порядке, и список выводится в обратном порядке.
В классе City описаны поля для хранения названий городов (Name)
и численность населения в тысячах человек (Pop). В нем реализованы
интерфейсы IComparable<City>, IComparer<City> (см. раздел
Интерфейсы), которые обеспечивают возможность упорядочения объектов.
Переопределен метод Equals, который обеспечивает поиск объектов
в списке. Сравнение и упорядочение объектов осуществляются по
полю Pop.
57

classCity:IComparable<City>,IComparer<City>
{
publicstringName{get;}
publicintPop{get;}
publicCity(stringn,intp)
{
Name=n;
Pop=p;
}
publicoverridestringToString()
{
return$"{Name,18},\t{Pop}";
}
//КомпаратордляупорядоченияобъектовCity.
public
{
if(x.Pop<y.Pop)
{
return‐1;
}
else
{
if(x.Pop==y.Pop)return0;
elsereturn1;
}
}
//КомпаратордляупорядоченияобъектовCity.
publicintCompareTo(Cityx)
{
returnCompare(this,x);
}
//СравнениеобъектовCityнаравенство.
publicoverrideboolEquals(objectobj)
{
if(this==null&obj==null)returntrue;
elseif(this!=null&obj==null|this==null&obj!=null)returnfalse;
return(objasCity).CompareTo(this)==0;
}
}
classProgram
intCompare(Cityx,Cityy)
58

{
staticvoidMain(string[]args)
{
//Создаемпустойсписок.
LinkedList<City>cities=newLinkedList<City>();
//ДобавляемвсписокэлементыметодамиAdd,AddLast,AddFirst,AddBefore.
cities.AddLast(newCity("Екатеринбург",1493));
cities.AddLast(newCity("НижнийНовгород",1252));
cities.AddLast(newCity("Казань",1257));
cities.AddFirst(newCity("Челябинск",1196));
cities.AddLast(newCity("Омск",1154));
//ДобавляемвсписокэлементыметодамиAddBefore,AddAfter.
LinkedListNode<City>node=
cities.AddBefore(node,newCity("Уфа",1125));
//ДобавляемвсписокэлементыметодамиAddBefore,AddAfter.
LinkedListNode<City>cur=cities.Find(newCity("",1196));
cities.AddAfter(cur,newCity("Новосибирск",1625));
//Выводимсписокнаконсоль.
foreach(varelincities)Console.WriteLine(el);
Console.WriteLine($"Макс.числ.={cities.Max()},элементов={cities.Count}");
//Фильтруемколлекциюнаосновепредиката,заданноголябда‐выражением.
//ВыделяемгороданабуквуН,ивыводимнаконсоль.
Console.WriteLine("Отфильтрованныйсписок:");
foreach(varelincities.Where(p=>p.Name[0]=='Н'))Console.WriteLine(el);
//Формируемколлекциюэлементов,переставленныхвобратномпорядке
//ивыводимнаконсоль.
IEnumerable<City>fil=cities.Reverse();
Console.WriteLine("Списоквобратномпорядке:");
foreach(varelinfil)Console.WriteLine(el);
}
}
Результатработыпрограммы:
Челябинск,1196
Новосибирск,1625
Екатеринбург,1493
НижнийНовгород,1252
Уфа,1125
Казань,1257
Омск,
Макс.числ.=Новосибирск,1625,элементов=7
Отфильтрованныйсписок:
Новосибирск,1625
НижнийНовгород,1252
1154
cities.Find(newCity("",1257));
59

Списоквобратномпорядке:
Омск,1154
Казань,1257
Уфа,1125
НижнийНовгород,1252
Екатеринбург,1493
Новосибирск,1625
Челябинск,1196
В следующем примере создается двусвязный список
LinkedList<City> и инициализируется с помощью конструктора, в ко-
торый в качестве параметра передается массив объектов класса City.
Список выводится на консоль. Затем список сортируется по полю
Name в порядке возрастания с помощью метода OrderBy и лямбдавыражения, элементы списка выводятся на консоль. После этого список сортируется по
полю Pop в порядке убывания с помощью метода
OrderByDescending и лямбда-выражения и элементы списка выводятся
на консоль. Затем с помощью метода Sum и лямбда-выражения подсчитывается и выводится на консоль суммарная численность населения городов, занесенных в список.
publicclassCity:IComparable<City>,IComparer<City>
{
publicstringName{get;}
publicintPop{get;}
publicCity(stringn,intp)
{
Name=n;
Pop=p;
}
publicoverridestringToString()
{
return$"{Name,18},\t{Pop}";
}
publicint
{
//СравнениеобъектовCity.
if(x.Pop<y.Pop)
{
return‐1;
Compare(Cityx,Cityy)
60
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
