Исследование MS Visual С#, страница 16

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

Изменять существующие элементы коллекции можно, обращаясь к ним с помощью операции выбора []. Вы можете проверить это, вставив до цикла foreach такую строку:

ht[ken] = "Movie maker";

Далее, вы можете вставить в конец существующего кода такой фрагмент:

ht.Clear();  //==== Удаляем все элементы

ht.Add ("Peter", 40000);   // Вставляем другие пары

ht.Add ("Andrew", 45000);

ht.Add ("Simon", 25000);

foreach (DictionaryEntry e in ht)

Console.WriteLine( "{0}  earns  {1}", e.Key, e.Value);

Удивительным кажется тот факт, что из приведенного кода можно убрать строку ht.Clear(); и, как ни в чем не бывало, продолжать работать, с уже неоднородной коллекцией пар. В ней будут присутствовать все пары, вставленные до этого момента. Тип элемента текущей пары можно выяснять на ходу. Такой сценарий реализован в следующей версии функции Main.

static void Main()

{

Man

  ken = new Man("Ken Wood",40),

  len = new Man("Lennie Tristano",50),

ben = new Man("Ben Webster",60);

Hashtable ht = new Hashtable();

ht.Add (ken, "Writer");  // Вставляем пары типа (Человек-Профессия)

ht.Add (len, "Pianist");

ht.Add (ben, "Sax player");

  //=== Изменяем второй элемент пары, обращаясь к нему с помощью индекса (ключа)

ht[ken] = "Movie maker";

Console.WriteLine ("\nTest change: {0}\n",ht[ken]);

  //==== Вставляем совсем другие пары

ht.Add ("Private", 1);   ht.Add ("Corporal", 2);

ht.Add ("Sergeant", 3);    ht.Add ("Lieutenant", 4);

ht.Add ("Captain", 5);

ht.Add (100, "My Debt");

int nMen = 0, nStrings = 0;

Console.WriteLine ("\nCollection has:\n");

foreach (DictionaryEntry e in ht)

{

  string type = e.Key.GetType().FullName; // Выясняем тип ключевого объекта

  if (type == "ManSpace.Man")   // Такой строкой система именует наших людей

     nMen++;

  else if (type == "System.String")

     nStrings++;

  else

     Console.WriteLine("Other: ({0},{1})",e.Key,e.Value);

}

Console.WriteLine("Men: {0}\nStrings: {1}",nMen,nStrings); // Подведем итог

}

Покажем, как пользоваться перечислителем при управлении коллекцией типа HashTable.

static void Main()

{

Hashtable ht = new Hashtable();

ht.Add (Math.PI, "PI");           // Заполняем коллекцию разнородными парами

ht.Add ("Computer Courses", "www.Avalon.ru");

ht.Add ("Zenith - Spartak", 3.2);

ht.Add ("Date", DateTime.Now);

ht.Add ("Mary", "I love you");

IDictionaryEnumerator en = ht.GetEnumerator(); // Перечислитель коллекции

while (en.MoveNext())    // Пользуемся им для прохода по всем парам

  Console.WriteLine(

     en.Key.ToString().PadLeft(25) + " : " + en.Value.ToString());

}

Здесь мы пользуемся структурой DateTime и ее статическим свойством Now, которое позволяет определить текущее локальное время в данном компьютере. Для разнообразия мы выбрали метод PadLeft класса string, который (a la Hollywood cast list) подбивает пробелами строки (слева), выравнивая тем самым правые края строк. Обратите внимание на отсутствие упорядоченности при выводе элементов коллекции (точнее, на ее непредсказуемый характер).

Упорядоченная последовательность

Если вы хотите иметь упорядоченную последовательность ключей и ассоциированных с ними значений, то можете воспользоваться услугами класса SortedList. Он сортирует последовательность ключей и поддерживает тем самым порядок расположения элементов во всей коллекции. Но в этом случае придется отказаться от полной свободы (скорее анархии) в выборе типов данных, которую мы продемонстрировали в предыдущем примере. Коллекция должна быть однородной. Термин List, использованный в имени типа коллекции, вероятно, намекает нам на то, что коллекция не является «чистым» представителем хешируемой таблицы. Действительно, при выборе элемента коллекции типа SortedList можно пользоваться как ключем, так и целочисленным индексом.

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

static void Main()

{

SortedList sl = new SortedList();    // Создаем упорядоченный ассоциативный список

sl.Add (Math.PI, "PI");

sl.Add (Math.E, "E");

sl.Add (Math.Sqrt (2), "Sqrt(2)");

sl.Add (Math.Pow (2, 24), "Colors");

IDictionaryEnumerator en = sl.GetEnumerator();

while (en.MoveNext())

  Console.WriteLine(

     en.Key.ToString().PadLeft(25) + " : " + en.Value.ToString());

}

Сортируемый список SortedList (на самом деле — ассоциативный контейнер) имеет свойства, некоторые из которых мы используем в следующем примере. Обратите также внимание на способ доступа к элементам контейнера с помощью индекса (GetKey(i) и GetByIndex(i)). Доступ с помощью ключа осуществляется обычным способом, но здесь важно не забыть ввести кавычки, которые, как и в языке С++, ограничивают строковые литералы.

static void Main()

{

SortedList sl = new SortedList();

sl.Add ("SortedList", "Sorted keys and values");// Пары типа (string, string)

sl.Add ("BitArray", "Compact array of bit values");

sl.Add ("ArrayList", "Dynamic array");