Работа с хэшами в Perl
Автор статьи не дает никаких гарантий, что код приведенный в ней будучи «преобразованный» с помощью Copy/Past заработает.
Все примеры работали на момент написания статьи.
Перевод достаточно вольный. Комментарии и предложения оставляйте в виде комментариев, на www.codenet.ru
- Инициализация (очистка) хэша
- Добавление пары ключ/значение в хэш
- Добавление нескольких пар ключ/значение в хэш
- Копирование хэшей
- Удаление одной пары ключ/значение
- Перебор всех пар ключ/значение
- Получение размера хэша
- Использование указателей на хэш
- Функция строящая хэш из хэшей и возвращающая указатель на хэш
- Доступ к хэшу из хэшей с помощью указателей. Вывод значений
- Функция строящая хэш из хешей из хешей и возвращающая указатель на хэш
- Доступ к хэшу из хэшей из хэшей с помощью указателей. Вывод значений.
- Вывод ключей и значений из хэша, полученного с помощью указателя
- Определение существования значения в хэше
Инициализация (очистка) хэша
Самый быстрый способ очистки — это присвоение пустого списка.
Реализация
my %hash = ();
Примечание
Часто спрашивают, как инициализировать указатель на хэш (hash ref).
Указатель — это скалярная переменная и инициализируется она соответствующим
образом. Например:
my $hash_ref; my $hash_ref = 0; # zero
Добавление пары ключ/значение в хэш
В примерах, приведенных ниже, кавычки вокруг ключей могут быть опущены, если ключи — идентификаторы.
Хэш:
Решение
$hash{ 'key' } = 'value'; # хэш $hash{ $key } = $value; # хэш, с использованием переменной
Указатель на хэш:
Решение
$href->{ 'key' } = 'value'; # указатель на хэш $href->{ $key } = $value; # указатель на хэш, с использованием переменной
Добавление нескольких пар ключ/значение в хэш
Решение
Эти операции эквивалентны, просто второй более читаем.
%hash = ( 'key1', 'value1', 'key2', 'value2', 'key3', 'value3' ); %hash = ( key1 => 'value1', key2 => 'value2', key3 => 'value3', );
Копирование хэшей
Решение
my %hash_copy = %hash; # копирование хэша my $href_copy = $href; # копирование указателя на хэш
Удаление одной пары ключ/значение
Не смотря на то что удаление хэша и удаление указателя на хэш, это разные операция,
обе они выполняются с помощью функции delete.
Решение
Хэш:
delete $hash{$key};
Указатель на хэш:
delete $hash_ref->{$key};
Перебор всех пар ключ/значение
Пример, приведенный ниже, печатает все пары ключ/значение.
Решение
Использование функции each с циклом while. Обратите внимание,
что each переберет пары в случайном порядке, но порядок будет совпадать с перебором
с помощью функций keys и values.
while ( my ($key, $value) = each(%hash) ) { print "$key => $value\n"; }
Для указатель на хэш небольшое отличие:
while ( my ($key, $value) = each(%$hash_ref) ) { print "$key => $value\n"; }
Решение
Использование функции keys с циклом for
for my $key ( keys %hash ) { my $value = $hash{$key}; print "$key => $value\n"; }
Пример
my $file = $ARGV[0] || "-"; my %from = (); open FILE, "< $file" or die "Can't open $file : $!"; while( <FILE> ) { if (/^From: (.*)/) { $from{$1}++ } # считаем повторение отправителя } close FILE; for my $sender ( sort keys %from ) { print "$sender: $from{$sender}\n"; }
Получение размера хэша
Решение
print "size of hash: " . keys( %hash ) . ".\n";
Solution
my $i = 0; $i += scalar keys %$hash_ref; # метод 1: явный скалярный контекст $i += keys %$hash_ref; # метод 2: неявный скалярный контекст
Использование указателей на хэш
Решение
sub foo { my $hash_ref; $hash_ref->{ 'key1' } = 'value1'; $hash_ref->{ 'key2' } = 'value2'; $hash_ref->{ 'key3' } = 'value3'; return $hash_ref; } my $hash_ref = foo(); print "ключи... ", sort keys %$hash_ref, "...\n";
Функция строящая хэш из хэшей и возвращающая указатель на хэш
Решение
sub foo { my ( $login, $p, $uid, $gid, $gecos, $dir, $s ); my %HoH = (); my $file = '/etc/passwd'; open( PASSWD, "< $file" ) or die "Can't open $file : $!"; while( <PASSWD> ) { ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' ); $HoH{ $login }{ 'uid' } = $uid; $HoH{ $login }{ 'gid' } = $gid; $HoH{ $login }{ 'dir' } = $dir; } close PASSWD; return \%HoH; }
Доступ к хэшу из хэшей с помощью указателей. Вывод значений
Решение
my $rHoH = foo(); my( $uid, $gid, $dir ); for my $login ( keys %$rHoH ) { $uid = $rHoH->{ $login }->{ 'uid' }; # метод 1. Более читабельный $gid = ${ $rHoH->{ $login } }{ 'gid' }; # метод 2 $dir = ${ ${ $rHoH }{ $login } }{ 'dir' }; # метод 3. Менее читабельный print "uid: $uid, gid: $gid, dir, $dir.\n"; }
Решение
my $rHoH = foo(); for my $k1 ( sort keys %$rHoH ) { print "k1: $k1\n"; for my $k2 ( keys %{$rHoH->{ $k1 }} ) { print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n"; } }
Функция строящая хэш из хешей из хешей и возвращающая указатель на хэш
Решение
sub foo { my %HoHoH = (); while( ... ) { if( /LOCATION:/ ) { ... } elsif( /MODULE:/ ) { $HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name; } elsif( $ARGS_ALLOWED ) { $HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value; } } return \%HoHoH; }
Доступ к хэшу из хэшей из хэшей с помощью указателей. Вывод значений.
Решение
my $rHoH = foo(); for my $k1 ( sort keys %$rHoHoH ) { print "$k1\n"; for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) { print "\t$k2\n"; for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) { print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n"; } } }
Вывод ключей и значений из хэша, полученного с помощью указателя
Решение
while( my ($k, $v) = each %$hash_ref ) { print "ключ: $k, значение: $v.\n"; }
Определение существования значения в хэше
Решение
print "Значение СУЩЕСТВУЕТ, но может быть не определено.\n" if exists $hash{ $key }; print "Значение ОПРЕДЕЛЕНО, но может быть false.\n" if defined $hash{ $key }; print "Значение TRUE\n" if $hash{ $key };
Пример
Допустим, мы выполнили SQL запрос, который может вернуть записи, содержащие значение NULL.
Перед тем как использовать результат запроса нам необходимо проверить, ОПРЕДЕЛЕНЫ ли полученные значения.
Обратите внимание, функция sql_fetch_hashref()
соединяется с сервером баз данных, подготавливает запрос,
выполняет его и получает указатель на хэш с помощью DBI функции fetchrow_hashref()
.
my $answers = 'a,b,c,d,e'; my $sql = "select max_time, $answers from questions " . 'where question_number=?'; my $hash_ref = sql_fetch_hashref( $sql, $q ); my @answers = split ',', $answers; my $max_time = $hash_ref->{max_time} || '60'; my $hash_ref_ans; for my $letter ( @answers ) { $hash_ref_ans->{ $letter } = $hash_ref->{ $letter } if defined $hash_ref->{ $letter }; }
Цикл for создает хэш только с ОПРЕДЕЛЕННЫМ парами ключ/значение.
Автор
Alex BATKO <abatko AT cs.mcgill.ca>
Спасибо всем, кто присылал комментарии и предложения.
См. еще
http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/
Комментарии