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