Титульная страница
ISO 9000 ISO 14000 Forum
Титульная страница
Цель системы качества
Управление качеством
ISO
ISO 9000
ISO 13485
ISO 14000
ISO 17025
OHSAS 18001
ISO 19011
Total Quality Management
Project Management
Фармацевтика
Отраслевые стандарты
Информационные технологии
Оформление документации
Ссылки 
Поиск на сайте
Forum
Реклама на сайте





| Содержание | Предисловие | Введение | Ссылки
| Глава 1 | Глава 2 | Глава 3 | Глава 4 | Глава 5 | Глава 6 | Глава 7 | Глава 8 | Глава 9 | Глава 10
| Глава 11 | Глава 12 | Глава 13 | Глава 14 | Глава 15 | Глава 16 | Глава 17 | Глава 18 | Глава 19
| Приложение А | Приложение Б | Приложение В | Приложение Г |

Глава 5

    В этой главе:


Хеши

Что такое хеш

Хеш* похож на массив, который мы рассматривали выше, тем, что представляет собой набор скалярных данных, отдельные элементы которого выбираются по индексному значению. В отличие от массива, индексные значения хеша — не малые неотрицательные целые, а произвольные скаляры. Эти скаляры (называемые ключами) используются для выборки значений из массива.

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

Хеш-переменные

Имя хеш-переменной состоит из знака процента (%) и буквы, за которой могут идти другие буквы, цифры и знаки подчеркивания числом от нуля и больше. Другими словами, часть имени после знака процента похожа на

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

** Модули типа IxHash и DB_fiIe обеспечивают некоторую степень упорядочения, но ценой существенного снижения производительности.

соответствующую часть имен скалярных переменных и массивов. Кроме того, точно так же, как нет никакой связи между $fred и @fred, хеш-переменная %fred не имеет ничего общего с названными объектами.

Чаще всего хеш создается и используется путем обращения к его элементам, а не ко всему хешу. Каждый элемент хеша — отдельная скалярная переменная, доступная через индекс, представляющий собой строковое значение и называемый ключом. Так, обращение к элементам хеша %fred производится путем указания $fred{ $ключ}, где $ключ — любое скалярное выражение. Вновь подчеркнем, что обращение к элементу хеша требует иного синтаксиса, нежели обращение ко всему хешу целиком.

Как и в случае с массивами, новые элементы хеша создаются путем присваивания значения:

$fred{"ааа"} == "bbb"; # создает ключ "ааа", значение "bbb" $fred(234.5} = 456.7; # создает ключ "234.5", значение 456.7

С помощью этих операторов в хеше создаются два элемента. При последующем обращении к элементам (по указанным ключам) возвращаются ранее записанные значения:

print $fred("ааа"); # выводит на экран "bbb" $fred{234.5) += 3; # делает значение равным 459.7

При обращении к несуществующему элементу возвращается значение undef (как и при обращении к отсутствующему элементу массива или к неопределенной скалярной переменной).

Литеральное представление хеша

У вас может возникнуть необходимость обратиться к хешу целиком — например, чтобы инициализировать его или скопировать в другой хеш. Фактически в Perl никакого литерального формата для хеша не предусмотрено, поэтому он просто представляется в виде списка. Каждая пара элементов этого списка (в котором всегда должно быть четное число элементов) задает ключ и соответствующее значение. Это развернутое представление может быть присвоено другому хешу, который затем воссоздаст тот же самый хеш. Другими словами:

@fred_list = %fred; # @fred_list получает значение

# ("ааа","bbb","234.5","456.7") %barney = @fred_list; # создать %barney как %fred %barney = %fred; # ускоренный метод выполнения этой задачи %smooth ” ("ааа","bbb","234.5","456.7") ;

# создать %smooth как %fred из литеральных значений

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

Одно из применений такого свертывания-развертывания — копирование хеш-значения в другую хеш-переменную:

%сору = %original; # копировать из %original в %сору

Используя операцию reverse, можно создать хеш, в котором ключи и значения поменяются местами:

%backwards = reverse %normal;

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

Хеш-функции

В этом разделе перечислены некоторые функции, предназначенные для обработки хешей.

Функция keys

Функция keys( %имя_хеша) выдает список всех текущих ключей, имеющихся в хеше %имя_хеша. Другими словами, применение этой функции эквивалентно возвращению всех элементов списка с нечетными номерами (первый, третий, пятый и т.д.) путем развертывания хеша %имя_хеша в списочном контексте, причем функция keys возвращает их именно в этом порядке. Если элементы в хеше отсутствуют, функция keys возвращает пустой список.

Применим эту функцию к хешу из предыдущих примеров:

$fred("aaa"} = "bbb";

$fred{234.5) = 456.7;

Olist = keys(%fred); # @list получает значение ("ааа",234.5) # или (234.5,"ааа")

Как и во всех остальных встроенных функциях, круглые скобки не обязательны: функция keys %fred полностью идентична keys (%fred).

foreach $key (keys (%fred)) ( # однократно для каждого значения хеша %fred

print "at $key we have $fred($key}\n"; # показать ключ и значение }

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

В скалярном контексте функция keys выдает число элементов (пар ключ-значение), содержащихся в хеше. Например, вы можете выяснить, пуст ли хеш, так:

if (keys(%xeni)) { # если keys() не равно 0:

...; # массив не пустой )

# ... или ...

while (keys(%xem) < 10) {

. . .; # продолжать цикл, пока меньше 10 элементов }

Для того чтобы узнать, пуст хеш или нет, нужно просто использовать функцию %хеш в скалярном контексте:

if (%хеш) ( # если "истина", в нем что-то есть

# что-то сделать )

Функция values

Функция values (%имя_массива) возвращает список всех текущих значений указанного массива в том же порядке, в каком функция keys ( %имя_массива} возвращает ключи. Как всегда, круглые скобки не обязательны. Например:

%lastname =0; # сделать %lastname пустым $lastname("fred"} = "flintstone";

$lastname("barney"} = "rubble";

Olastnames = values(tiastname); # получить значения

Массив @lastnames будет содержать либо значения ("flintstone", "rubble"), либо ("rubble", "flintstone").

Функция each

Для выполнения цикла над всем хешем (т.е. для проверки каждого его элемента) можно использовать функцию keys и получать значения по возвращаемым ею ключам. Действительно, этот метод широко используется, но есть и более эффективный способ — функция each ( %имя_хеша), которая возвращает пару ключ-значение как двухэлементный список. При каждом вычислении этой функции для одного хеша возвращается очередная пара ключ-значение, пока не будут проверены все элементы. Если пар больше нет, each возвращает пустой список.

* Можно, в принципе, с помощью среза, но здесь о срезах мы не говорим.

Например, чтобы пройти по хешу %lastname из предыдущего примера, нужно использовать нечто такое:

while ( ($first,$last) = each(%lastname)) {

print "The last name of $first is $last\n";

}

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

Функция delete

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

%fred = ("aaa","bbb",234.5,34.56); # добавить в %fred два элемента delete $fred("aaa"}; # теперь в хеше %fred только одна пара ключ-значение

Срезы хешей

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

$score("fred"} - 205;

$score("barney"} = 195;

$scoref"dino"} = 30;

Все это можно записать одной строкой:

($score("fred"},$score("barney"),$score("dino")) ° (205,195,30);

Но даже она слишком длинна, поэтому давайте используем срез хеша:

$score{"fred","barney","dino"} = (205,195,30);

Вот так гораздо короче. Можно сочетать использование среза хеша и интерполяции переменных:

@players = qwffred barney dino);

print "scores are: @score(@players}\n";

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

@league{keys %score( = values %score;

Здесь значения хеша %score сливаются с хешем %league. Это эквивалентно выполнению гораздо более медленной операции:

%league = (%league, %score); = # слить %score с %league

Упражнения

Ответы к упражнениям даны в приложении А.

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

Ввод

Вывод

red green blue

apple

leaves ocean

 

2. Напишите программу, которая читает ряд слов (по одному в строке) до конца файла, а затем выводит на экран сводку о том, сколько раз встретилось каждое слово. (Дополнительная задача: отсортируйте появляющиеся на экране слова по их ASCII-значениям в порядке возрастания последних.)




|     Назад     |     Вперед     |


| Содержание | Предисловие | Введение | Ссылки
| Глава 1 | Глава 2 | Глава 3 | Глава 4 | Глава 5 | Глава 6 | Глава 7 | Глава 8 | Глава 9 | Глава 10
| Глава 11 | Глава 12 | Глава 13 | Глава 14 | Глава 15 | Глава 16 | Глава 17 | Глава 18 | Глава 19
| Приложение А | Приложение Б | Приложение В | Приложение Г |
Rambler's Top100
Hosted by uCoz