Объединить два или более фрагментов хэша, т.е. только выбранные ключи из хэшей

Я пишу кусок кода, который получает аргументы %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 }
Другие вопросы по тегам