Иллюстрированный самоучитель по Perl

       

Ассоциативные массивы


Ассоциативные массивы,

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

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

В программе хеши задаются аналогично массивам скаляров с помощью конструктора, представляющего собой список, заключенный в круглые скобки, в котором пары ключ/значение следуют друг за другом:

(ключ_1, значение_1, ключ_2, значение_2, ... , ключ_п, значение_п)

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

хеш-переменными.

Ассоциативный массив создается во время операции присвоения такой переменной списка значений:

%т = ("Имя", "Ларри", "Фамилия", "Уолл");



Замечание

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

В ассоциативном массиве %т ключами являются строки "имя" и "Фамилия", а ассоциированными с ними значениями, соответственно, "ларри" и "УОЛЛ". Теперь, чтобы получить значение, соответствующее какому-либо ключу, следует воспользоваться конструкцией:

$т{"ключ"}




Обратите внимание, что при работе с

элементом

ассоциативного массива, символ хеш-переменной "%" заменяется на символ скалярной переменной "$". Аналогично мы поступали и при ссылке на элемент массива скаляров. Единственное отличие — ключ задается в фигурных скобках. Итак, чтобы, например, присвоить некоторой скалярной переменной значение элемента хеш-массива %т, следует воспользоваться следующим оператором:

$surname = $m{"Фамилия"};

Теперь скалярная переменная $ surname имеет в качестве своего значения строку

Уолл.





Замечание





Интерпретация списка как последовательности пар ключ/значение происходит

только

при операции его присвоения хеш-переменной. Если список, присваивается переменной массива скаляров, то он интерпретируется как простая последовательность значений элементов массива.

Инициализация хеш-массива с помощью списка, элементы которого отделяются друг от друга символом запятая ",", не очень удобно, так как в длинном списке трудно выделять соответствующие пары ключ/значение. Для улучшения наглядности пару ключ/значение можно соединить последовательностью символов "=>", заменив ей разделяющую запятую в списке. По правде говоря, и запятая ",", и символы "=>" представляют собой знаки операций в Perl, причем операция "=>" эквивалентна операции "запятая" с той лишь разницей, что ее левый операнд всегда интерпретируется как строковый литерал, даже если он не заключен в кавычки.





Замечание





Интерпретация левого операнда операции "=>" как строкового литерала справедлива для последовательности символов, в которой используются буквы латинского алфавита. Буквы русского алфавита вызовут ошибку интерпретации, так как последовательность символов не будет распознана как слово языка Perl.

Рассмотренный нами ранее хеш-массив %т можно инициировать и таким способом:

%т = (

"Имя" => "Ларри",

"Фамилия" => "Уолл" );



Если бы мы хотели в качестве индексов имени и фамилии использовать английские слова name и surname, то этот же ассоциированный массив можно было бы задать следующим оператором:

%т = (

Name => "Ларри",

Surname => "Уолл" );

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

$т{"Имя"} = "Гарри"; # Изменили значение существующего элемента. $т{"Телефон"} = "345-56-78"; # Добавили новый элемент.

Если при использовании подобной конструкции ассоциативный массив еще не существовал, то при выполнении операции присваивания сначала будет создан сам массив, а потом присвоится значение его элементу. Ассоциативные массивы, как и массивы скаляров, являются динамическими: все добавляемые элементы автоматически увеличивают их^размерность.

Удалить элемент ассоциативного массива можно только с помощью встроенной функции delete:

delete($m{"Телефон"}); # Удалили элемент с ключом "Телефон".





Совет





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

При работе с ассоциативным массивом часто требуется организовать перебор по множеству всех его ключей или значений. В языке существуют две встроенные функции — keys и values, которые представляют в виде списка, соответственно, ключи и значения ассоциативного массива, Следующий фрагмент программы

print keys(%m), "\n"; # Печать ключей. print values(%m), "\n";

# Печать значений.

отобразит на экране монитора строку ключей и строку значений массива %т

Фамилия Имя Телефон УоллЛарри345-56-11

Обратите внимание, что они отображаются не в том порядке, как задавались с помощью конструктора массива.







Замечание





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

Итак, хеш-массивы позволяют обращаться к своим элементам не с помощью числового индекса, а с помощью индекса, представленного строкой. Но что же здесь такого замечательного, какие возможности предоставляет подобная конструкция? Огромные. И первое, что приходит на ум, — это использовать ключи как аналог ключей реляционных таблиц. Правда, хеш-массивы не позволяют непосредственно хранить запись, а только один элемент, но и этого уже достаточно, чтобы создать достаточно сложные структуры данных (пример 3.7).

#! peri -w %friend = (

"0001", "Александр Иванов",

"0002", "Александр Петров",

"0003", "Александр Сидоров" ); %city = (

"0001", "Санкт-Петербург",

"0002", "Рязань", '"0003", "Кострома" ) ; %job = ( •

"0001", "учитель",

"0002", "программист",

"0003", "управляющий"

) ; . ' $person = "0001";

print "Мой знакомый $friend{$person}\n"; print "живет в городе $city{$person}\n"; print "и имеет профессию $job{$person}.\п";

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

Мой знакомый Александр Иванов живет в городе Санкт Петербург и имеет профессию учитель.

Если изменить значение переменной $person на другой ключ, то отобразится связанная информация о другом человеке.



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

Связанный список —

это простейшая динамическая структура данных, расположенных в определенном порядке. Каждый элемент связанного списка состоит из некоторого значения, ассоциированного с данным элементом, и ссылки на следующий элемент списка. Последний элемент списка не имеет ссылки на следующий, что обычно реализуется в виде пустой ссылки. Для окончательного задания связанного списка следует объявить переменную, указывающую на первый элемент списка, которую называют заголовком. Для связанного списка определяются операции выбора, удаления и добавления элемента списка относительно заданного. Графически связанный список можно представить так, как показано на рис. 3.1, где указатель на следующий элемент обозначен серым цветом.









Рис 3.1. Графическое представление связанного списка






С помощью хеш-массивов связанный список реализуется просто. Для этого следует значение элемента задать в качестве ключа для следующего за ним элемента списка, определив таким образом указатель на следующий элемент. Значением последнего элемента в хеш-массиве (с ключом, равным значению последнего элемента связанного списка) будет пустая строка "". Переменная-заголовок должна иметь значение, равное ключу первого элемента списка. В примере 3.8 показана реализация связанного списка, а также добавление нового элемента.

%linked_list = ( "начало" => "первый", "первый" => "третий",

"третий" => ""

);

$header = "начало";

# Добавление элемента со значением "второй"

# после элемента со значением "первый".

$temp = $linked_lis.t{ "первый"};

# Запомнили старый, указатель ., $linked_list{"второй"} = $temp;

# Добавили новый элемент. $linked_list{"первый"} = "второй";



# Указатель на новый элемент.

$item = $header;

# Печать нового связанного.списка.

while ($linked_list{$item}) { # Пока не дойдем до пустой строки ""

print $linked_list{$item}, "\n"; # будем печатать значения элементов.

$item = $linked_list{$item};

}

Результатом выполнения программы примера 3.8 будет печать значений элементов нового связанного списка в следующем порядке:

первый второй третий

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


Содержание раздела