Доступ к элементам
Проверка хэша на наличие элемента:
%hash = (
'шляпа' => 'серая',
'водка' => 'горькая',
'вобла' => 'вкусная');
if(exists($hash{"дождь"})){
print "Элемент найден";
}
else{
print "Элемент не найден";
}
Удалить элемент из хэша можно при помощи функции delete:
%hash = (
'шляпа' => 'серая',
'водка' => 'горькая',
'вобла' => 'вкусная');
delete($hash{"шляпа"});
if(exists($hash{"шляпа"})){
print "Элемент найден";
}
else{
print "Элемент не найден";
}
Функция delete может вызываться для среза хэша, что приводит к удалению всех указанных ключей:
delete @hash{'шляпа','водка','вобла'}; см. perlfunc(1)
Если нужно найти совпадающие ключи или не входящие в другй хэш, то надо организовать перебор ключей хэша при помощи keys и проверять, если ли текущий ключ в другом хэше. Поиск совпадающих ключей:
my @common = ();
foreach(keys %hash1){
push(@common, $_) if exists $hash2{$_};
}
Поиск ключей, отсутствующих в другом хэше:
my @test = ();
foreach(keys %hash1){
push(@test, $_) unless exists $hash2{$_};
}
Если keys вызывается для хэша, ключи которого представляют собой ссылки, то возвращаемые ей ссылки не работают. Ключи преобразуются в строки, т.е. интерпретируются так, словно они заключены в кавычки, при работе со ссылками они теряют свои свойства. После преобразования в строку ссылка имеет вид
Class::Somewhere=HASH(0x72048)
ARRAY(0x72048)
Преобразованную ссылку нельзя вернуть к прежнему виду, т.к. она из ссылки превратилась в строку. Нужно создать специальный хэш, ключами которого являются ссылки, преобразованные в строки, и значениями - настоящие ссылки.Можно воспользоваться модулем Tie::RefHash. Пример показывает использование объектов ввода/вывода для работы с файловыми манипуляторами.
use Tie::RefHash;
use IO::File;
tie %name, "Tie::RefHash";
foreach $filename("/etc/termcamp/", "/vminux", "/bin/cat"){
$fh = IO::File->("<$filename") or next;
$name{$fh} = $filename;
}
print "open files: ", join(", values %name", "\n");
foreach $file(keys %name){
seek($file, 0, 2);
printf("%s is %d bytes long.\n", $name{$file}, $tell{$file});
}
Если в качестве ключа использована неопределенная величина undef, то она преобразуется в пустую строку. undef является вполне допустимым значением в хэше. Но при выборке значения для ключа, отсутствующего в хэше perl выдаст undef. Проверить наличие ключа можно так: exist($hash{$key}); определенность ассоциированного значения: defined($hash{$key}); истинность: if($hash{$key});. Иногда undef нужно сохранять в кэше, т.е. ключ есть, но с ним не связано ничего полезного, например программа, определяющая размер файлов из переданного списка:
%name =();
while(<>){
chomp;
next if exist $name{$_};
$name{$_} = -s $_;
}
Этот код позволяет пропустить несуществующие и нулевые файлы, но записанные в исходном списке.
Хэши с несколькими значениями, ассоциированными одним ключом. Т.к. скалярные величины, содержащиеся в хэше, могут быть ссылками(которые могут быть скалярами), то ассоциировать несколько значений одним ключом можно сохранив в $hash($key) ссылку на массив со значениями, ассоциированными с ключом $key. Операции с хэшами(вставка, удаление, перебор и проверка существования(undef)) переписываются для операций с массивами(push, splice и foreach). Пример, реализующий вставку в хэш(обрабатывает выходные данные команды who(1) и выводит краткий список пользователей с терминалами, на которых они зарегестрированы):
%ttys=();
open (WHO, "who|");
while(){
($user, $tty) = split;
push(@ {$ttys{$user}}, $tty);
}
foreach $user (sort keys %ttys){
print "$user: @{$ttys{$user}}\n"
}
в строке push содержится версия $tty{$user} = $tty для многозначного хэша. Все имена терминалов интерполируются в строке print @{$ttys{$user}}.
Пример программы, которая на название предмета выдает его свойство и наоборот:
#!/usr/bin/perl -w
$vziat = shift @ARGV or die $!;
%svojstvo = (
"malina" => "vkusnaia",
"svekla" => "krasnaya",
"kozmodrom" => "nebolshoy",
"magazin" => "dvuhetagnij");
%predmet = reverse %svojstvo;
if (exists $svojstvo{$vziat}){print "$vziat," ", $svojstvo{$vziat}\n";}
elsif (exists $predmet{$vziat}){print "$vziat," ", $predmet{$vziat}\n";}
например если ввести в терминале:
bash-2.03$ ./1.pl malina
то скрипт выдаст:
malina vkusnaia
или
bash-2.03$ ./1.pl vkusnaia
vkusnaia malina
В чем различие delete и undef для хешей?
Хеши являются парами скаляров, первый - ключ, второй значение.
Ключ может быть строкой, в то время как значением хеша может
быть любой вид скаляра: строка, число или ссылка. Если ключ
содержится в хеше, то exists($key) возвратит истину. Значение для
какого-то конкретного ключа может быть undef'ом, и $array{$key}
возвратит так-же undef, но exists($key) возвратит истину.
Иными словами в хеше может быть реализована связка ('$key', 'undef')
В качестве примера можно привести следующую таблицу %ary:
keys values
+------+------+
| a | 3 |
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
Этот хеш выглядит примерное так:
$ary{'a'} true
$ary{'d'} false
defined $ary{'d'} true
defined $ary{'a'} true
exists $ary{'a'} true (perl5 only)
grep ($_ eq 'a', keys %ary) true
Если теперь сказать
undef $ary{'a'}
То таблица будет читаться следующим образом:
keys values
+------+------+
| a | undef|
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
И теперь логические состояния в хеше уже немного другие,
изменения показаны регистром
$ary{'a'} FALSE
$ary{'d'} false
defined $ary{'d'} true
defined $ary{'a'} FALSE
exists $ary{'a'} true (perl5 only)
grep ($_ eq 'a', keys %ary) is true
Отсюда следует вывод, что можно держать значение undef'ом,
но ключ всегда должен быть определен.
Теперь рассмотрим операцию удаления элемента из хеша:
delete $ary{'a'}
после этого таблица будет выглядеть так:
keys values
+------+------+
| x | 7 |
| d | 0 |
| e | 2 |
+------+------+
Состояния элементов в хеше уже другие,
изменения показаны, как и в предыдущем примере, различающимся регистром.
$ary{'a'} is false
$ary{'d'} is false
defined $ary{'d'} is true
defined $ary{'a'} is false
exists $ary{'a'} is FALSE (perl5 only)
grep ($_ eq 'a', keys %ary) is FALSE
from: