Хеш * схожий на масив, який ми розглядали вище, тим, що являє собою набір скалярних даних, окремі елементи якого вибираються по індексному значенням. На відміну від масиву, індексні значення хешу - не малі невід'ємні цілі, а довільні скаляри. Ці скаляри (звані ключами) використовуються для вибірки значень з масиву.
Елементи хешу не варті в якомусь конкретному порядку. Можете розглядати їх як стопку бібліографічних карток. Верхня половина кожної картки - це ключ, а нижня - значення. Кожен раз, коли ви ставите в хеш значення, створюється нова картка. Коли потрібно змінити значення, ви вказуєте ключ, і 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
При зверненні до неіснуючого елементу повертається значення 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 повертає порожній список.
Застосуємо цю функцію до хешу з попередніх прикладів:
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 (% імя_массіва) повертає список всіх поточних значень зазначеного масиву в тому ж порядку, в якому функція keys (% імя_массіва> повертає ключі. Як завжди, круглі дужки не обов'язкові. Наприклад:
% Lastname = 0; # Зробити% lastname порожнім $ lastname ( "fred"> = "flintstone";
Olastnames = values (tiastname); # Отримати значення
Масив @lastnames буде містити або значення ( "flintstone", "rubble"), або ( "rubble", "flintstone").
Для виконання циклу над усім хешем (тобто для перевірки кожного його елемента) можна використовувати функцію keys і отримувати значення по повертається нею ключам. Дійсно, цей метод широко використовується, але є і більш ефективний спосіб - функція each (% імя_хеша), яка повертає пару ключ-значення як двоелементний список. При кожному обчисленні цієї функції для одного хешу повертається чергова пара ключ-значення, поки не будуть перевірені всі елементи. Якщо пар більше немає, each повертає порожній список.
* Можна, в принципі, за допомогою зрізу, але тут про зрізах ми не говоримо.
Наприклад, щоб пройти по хешу% lastname з попереднього прикладу, потрібно використовувати щось таке:
while (($ first, $ last) = each (% lastname))
print "The last name of $ first is $ last \ n";
Присвоєння нового значення всьому хешу змушує функцію each перейти в його початок. Додавання елементів в хеш і видалення з нього елементів в ході виконання циклу цілком може "заплутати" функцію each (і вас, напевно, теж).
% Fred = ( "aaa", "bbb", 234.5,34.56); # Додати в% fred два елементи delete $ fred ( "aaa">; # тепер в хеше% fred тільки одна пара ключ-значення
Як і в випадку зі змінною-масивом (або обліковим літералом), можна скористатися зрізом хешу, що дасть можливість звертатися не до одного його елементу, а одночасно до набору елементів. Візьмемо, наприклад, результати гри в кеглі:
Все це можна записати одним рядком:
Але навіть вона занадто довга, тому давайте використаємо зріз хешу:
Ось так набагато коротше. Можна поєднувати використання зрізу хешу і інтерполяції змінних:
@players = qwffred barney dino);
print "scores are: @score (@players> \ n";
Зрізи хешів можна також використовувати для злиття невеликого хешу з більшим. У цьому прикладі менший хеш має пріоритет в тому сенсі, що при наявності ключів-дублікатів використовується значення з меншого хешу:
Тут значення хешу% score зливаються з хешем% league. Це еквівалентно виконанню набагато більш повільної операції:
% League = (% league,% score); = # Злити% score з% league
1. Напишіть програму, яка читає рядок, а потім виводить цей рядок і відповідне їй значення відповідно до наведеної нижче таблиці:
2. Напишіть програму, яка читає ряд слів (по одному в рядку) до кінця файлу, а потім виводить на екран зведення про те, скільки разів зустрілося кожне слово. (Додаткове завдання: відсортуйте з'являються на екрані слова по їх ASCII-значень в порядку зростання останніх.)