Объединить два или более фрагментов хэша, т.е. только выбранные ключи из хэшей
Я пишу кусок кода, который получает аргументы %args
и имеет конфигурацию %conf
, Мне нужно передать определенные значения из обоих этих хэшей в другой модуль Perl, в то время как другие имеют отношение только к моему собственному коду.
Как объединить два (или более) фрагмента хэшей или объединить хэши, сохраняя при этом элегантно выбранные ключи?
Важные моменты:
- Список желаемых ключей может быть использован как список или сохранен в массиве.
- Значения от
%args
переопределит те из%conf
, - Ключи, не содержащиеся в
%args
ни%conf
не должны содержаться в%result
,
Пример ввода:
my %conf = (
path => '/usr/local/bin/',
size => 42,
other => 'value', # isn't used
);
my %args = (
path => '~/bin/', # overrides $conf{path}
foo => 'bar',
);
my @keys = qw<path size foo bar>; # 'bar' isn't contained in either hash!
Ожидаемый результат:
my %result = (
path => '~/bin/', # from $args{patħ}
size => 42,
foo => 'bar',
);
Для простого слияния этого достаточно:
my %result = ( %conf, %args );
Простой фрагмент хеша также прост:
my %slice = map { $_ => $hash{$_} } qw<foo bar baz>;
Приведение к существующим ключам уже требует временной переменной:
my %keys = map { $_ => 1 } qw<foo bar baz>;
grep { $keys{$_} } %hash;
Но все это становится довольно сложным:
my @keys = qw<foo bar baz>;
my %keys = map { $_ => 1 } @keys;
my %result = (
map( { $_ => $conf{$_} } grep { $keys{$_} } keys %conf ),
map( { $_ => $args{$_} } grep { $keys{$_} } keys %args ),
);
Есть какой-нибудь более хороший способ кодировать это?
1 ответ
Обновить
Это ответ на ваш исправленный вопрос. Мои лучшие попытки написать что-то чистое просто удаляют все элементы объединенного хэша, которые не находятся в @keys
, используя промежуточный %wanted
хэш, чтобы описать, какие ключи хеша появляются в массиве
use strict;
use warnings 'all';
# Set up test data
my %conf = (
path => '/usr/local/bin/',
size => 42,
other => 'value', # isn't used
);
my %args = (
path => '~/bin/', # overrides $conf{path}
foo => 'bar',
);
my @keys = qw/ path size foo bar /; # 'bar' isn't contained in either hash!
# Combine and select
my %wanted = map { $_ => 1 } @keys;
my %result = (%conf, %args);
delete @result{ grep { not $wanted{$_} } keys %result };
# Display the result
use Data::Dump;
dd \%result;
выход
{ foo => "bar", path => "~/bin/", size => 42 }
оригинал
Это, кажется, отвечает всем требованиям. Я скопировал тестовые данные из вашего поста
Два хеша объединяются в
%join
, с%args
переопределение%conf
поставив его на второе место в списке назначенийТогда массив
%result
построен с использованием срезов, чтобы извлечь необходимые элементы из%join
Я использовал Data:: Dump только для отображения результатов предыдущего кода
Обратите внимание, что если есть строка в
@keys
который не появляется ни в одном хеше, тогда он будет включен в%results
со значениемundef
"Список желаемых ключей может быть использован как список или сохранен в массиве".
Это очень расплывчатое требование. Чтобы это решение работало, вам нужен массив ключей, поэтому просто сохраните ваш список в виде массива
use strict;
use warnings 'all';
# Set up test data
my %conf = (
path => '/usr/local/bin/',
size => 42,
other => 'value', # isn't used
);
my %args = (
path => '~/bin/', # overrides $conf{path}
foo => 'bar',
);
my @keys = qw/ path size foo /;
# Combine and select
my %join = (%conf, %args);
my %result;
@result{@keys} = @join{@keys};
# Display the result
use Data::Dump;
dd \%result;
выход
{ foo => "bar", path => "~/bin/", size => 42 }