Ассоциативные массивы, называемые также хеш-массивами
или просто хешами, — это то, чем гордятся программисты на
языке 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.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 будет печать значений элементов нового связанного списка в следующем порядке:
первый второй третий
Этот пример только демонстрационный, чтобы показать легкость реализации подобной динамической структуры. При действительной реализации связанного списка следует все возможные действия оформить в виде функций, которые в дальнейшем использовать для работы со связанным списком.