PERL - статьи

Доступ к элементам


Проверка хэша на наличие элемента:

%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:


Содержание раздела