Подтвердить что ты не робот

Как я могу получить только часть хэша в Perl?

Есть ли способ получить суб-хэш? Нужно ли использовать хэш-фрагмент?

Например:

%hash = ( a => 1, b => 2, c => 3 );

Я хочу только

%hash = ( a => 1, b => 2 );
4b9b3361

Ответ 1

Хэш-фрагменты возвращают значения, связанные со списком ключей. Чтобы получить хэш-срез, вы меняете сигил на @и предоставляете список ключей (в данном случае "a" и "b"):

my @items = @hash{"a", "b"};

Часто вы можете использовать оператор слова котировки для создания списка:

my @items = @hash{qw/a b/};

Вы также можете назначить хэш-фрагмент, поэтому, если вы хотите новый хэш, содержащий подмножество другого хэша, вы можете сказать

my %new_hash;
@new_hash{qw/a b/} = @hash{qw/a b/};

Многие люди будут использовать map вместо хэш-фрагментов:

my %new_hash = map { $_ => $hash{$_} } qw/a b/;

Начиная с Perl 5.20.0, вы можете получить ключи и значения за один шаг, если вместо синтаксиса @используется сигль%:

my %new_hash = %hash{qw/a b/};

Ответ 2

Возможно, вам захочется собрать список желаемых ключей:

my @keys = qw(a b);

И затем используйте цикл для создания хэша:

my %hash_slice;
for(@keys) {
  $hash_slice{$_} = %hash{$_};
}

Или:

my %hash_slice = map { $_ => $hash{$_} } @keys;

(Мое предпочтение - второе, но лучше, чем вам нравится).

Ответ 3

Еще один способ:

my @keys = qw(a b);
my %hash = (a => 1, b => 2, c => 3);
my %hash_copy;
@hash_copy{@keys} = @hash{@keys};

Ответ 4

Слишком много функционального программирования сначала заставляет меня думать о zip.

С List:: MoreUtils установлен,

use List::MoreUtils qw(zip);

%hash = qw(a 1 b 2 c 3);
@keys = qw(a b);
@values = @hash{@keys};
%hash = zip @keys, @values;

К сожалению, прототип List:: MoreUtils zip запрещает

zip @keys, @hash{@keys};

Если вы действительно хотите избежать промежуточной переменной, вы можете

zip @keys, @{[@hash{@keys}]};

Или просто напишите свой собственный zip без проблемного прототипа. (Это не обязательно List:: MoreUtils вообще.)

sub zip {
    my $max = -1;
    $max < $#$_and $max = $#$_ for @_;
    map { my $ix = $_; map $_->[$ix], @_; } 0..$max;
}

%hash = zip \@keys, [@hash{@keys}];

Если вы собираетесь мутировать на месте,

%hash = qw(a 1 b 2 c 3);
%keep = map +($_ => 1), qw(a b);
$keep{$a} or delete $hash{$a} while ($a, $b) = each %hash;

избегает дополнительного копирования, которое требует решения map и zip. (Да, мутируя хеш, когда вы повторяете его, это безопасно... до тех пор, пока мутация удаляет только последнюю итерационную пару.)

Ответ 5

FWIW, я использую Moose:: Autobox здесь:

my $hash = { a => 1, b => 2, c => 3, d => 4 };
$hash->hslice([qw/a b/]) # { a => 1, b => 2 };

В реальной жизни я использую это, чтобы извлечь "имя пользователя" и "пароль" из представления формы и передать это Catalyst $c->authenticate (который ожидает, в моем случае, hashref, содержащего имя пользователя и пароль, но ничего еще).

Ответ 6

Новое в perl 5.20 - это хэш-срезы, возвращающие ключи, а также значения, используя%, как на последней строке:

my %population = ('Norway',5000000,'Sweden',9600000,'Denmark',5500000);
my @slice_values = @population{'Norway','Sweden'}; # all perls can do this
my %slice_hash   = %population{'Norway','Sweden'}; # perl >= 5.20 can do this!

Ответ 7

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