Как вы сопоставляете массив [key1, val1] с хэшем {key1 => val1} в perl?


Проблема в том, что у меня есть массив, который содержит пары значений ключей в качестве элементов в массиве, и я должен каким-то образом разделить их на пары значений ключей => в хэше.

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

my $HASH;
my $ARRAY = [ key1, val1, key2, val2, __key3__, val3, __key4__, val4 ];
   my @keys = map{ $ARRAY[ $_*2   ] } 0 .. int($#ARRAY/2);
   my @vals = map{ $ARRAY[ $_*2+1 ] } 0 .. int($#ARRAY/2);

   my $i = 0;
   #filter for keys that only have __key__ format
    for $key (@keys){
      if( $key && $key =~ m/^__(.*)__$/i ){
       $HASH{$1} = $vals[$i];
      }
     $i++;
    }
   # only key3 and key4 should be in $HASH now

Я нашел этот пример кода , который, как мне кажется, близок к тому, что я ищу, но я не могу понять, как реализовать нечто подобное над массивом, а не перебирание строк текстового файла:

$file = 'myfile.txt'
open I, '<', $file
my %hash;
%hash = map { split /s*,s*,/,$_,2 } grep (!/^$/,<I>);
print STDERR "[ITEM] $_ => $hash{$_}n" for keys %hash;
Может ли кто-нибудь из вас, гуру perl, помочь мне понять, как лучше всего это сделать? Даже если бы я мог каким-то образом объединить все элементы в строку, а затем разделить каждый второй символ пробела-это тоже могло бы сработать, но пока я застрял!
5 4

5 ответов:

Это очень просто:

use strict; use warnings;
use YAML;

my $ARRAY = [qw(key1 val1 key2 val2 __key3__ val3 __key4__ val4)];
my $HASH =  { @$ARRAY };

print Dump $HASH;

Вывод:

C:\Temp>
---
__key3__: val3
__key4__: val4
key1: val1
key2: val2
my $ARRAY = [ qw(key1 val1 key2 val2 key3 val3 key4 val4) ];
my $HASH = { @$ARRAY };

В найденном примере кода часть <I> считывает весь файл и возвращает список в grep. grep обрабатывает список и передает его на карту. Затем Map создает свой собственный список, и этот список присваивается хэшу.

При назначении списка хэшу предполагается, что список является четным списком пар ключ/значение.

Не имеет значения, откуда берется этот список, он может быть результатом команды map, grep или split. Это может быть прямо из файла, это может быть ... хранится в массиве.

Ваша строка:

my $HASH = ();

Не делает ничего полезного. Написание my $HASH; точно такое же.

В этой точке $HASH не определено. Когда у вас есть неопределенное значение и вы разыменуете его как хэш, %$HASH, неопределенное значение станет хэшем.

Вы можете сделать это явным, написав:

my $HASH = {};  # note the curly braces and not parens

Если у вас есть список пар значений ключей в массиве:

%$HASH = @array;

Если у вас есть список ключей и список значения:

@$HASH{@keys} = @values;

В соответствии с вашим вопросом, Вот один простой способ создания хэша из массива при фильтрации значений:

my $HASH = {};
my $ARRAY = [ qw(key1 val1 key2 val2 __key3__ val3 __key4__ val4) ];

{my @list = @$ARRAY;  # make a copy since splice eats the list
    while (my ($k, $v) = splice @list, 0, 2) {
        if ($k =~ /^__(.+)__$/) {
            $$HASH{$1} = $v
        }
    }
}

use Data::Dumper;

print Dumper($HASH);

Который печатает:

$VAR1 = {
          'key4' => 'val4',
          'key3' => 'val3'
        };
Если вы хотите сделать это все в одной строке, вы можете использовать функцию mapn из моего модуля List::Gen, которая является функцией, подобной map, но которая позволяет вам перемещаться по списку с любым размером шага, а не только по одному элементу за раз.
use List::Gen 'mapn';

%$HASH = mapn {/^__(.+)__$/ ? ($1, $_[1]) : ()} 2 => @$ARRAY;
Я не знал, что вы можете сбросить массив, и хэш поймет это.

Нет ничего волшебного в значениях, которые приходят из массива. Гашишу тут нечего выяснять.

Если вы назначите хэшу список, он очистит хэш, а затем обработает список как список пар ключ-значение, из которых нужно инициализировать хэш. Итак

%hash = ( foo => 1, bar => 2 );

Эквивалентно

my @anon = ( foo => 1, bar => 2 );
%hash = ();
while (@anon) {
   my $key = shift(@anon);
   my $val = shift(@anon);
   $hash{$key} = $val;
}

Список есть список. Не имеет значения, был ли он произведен с помощью списка / запятой op

x => "foo", y => "bar"

Используя qw()

qw( x foo y bar )

Или с помощью массива

@array

Таким образом, это означает, что все нижеследующие являются одинаковыми.

%hash = ( x => "foo", y => "bar" );
%hash = qw( x foo y bar );
%hash = @array;  # Assuming @array contains the correct values.

И так же

$hash = { x => "foo", y => "bar" };
$hash = {qw( x foo y bar )};
$hash = { @array };  # Assuming @array contains the correct values.

Поскольку ваш конкретный случай уже получил ответ, я подумал, что отвечу на случай того, что я взял ваш вопрос, чтобы задать. Я ожидал увидеть массив пар, подобных [ key => $value ], и что вы хотите поместить либо в массив хэшей, либо в хэш:

Этот ответ звучит так:

my %hash = map { @$_ } [[ key1 => $value1 ], [ key2 => $value2 ], ... ];
my @ha   = map {; { @$_ } } [[ key1 => $value1 ], [ key2 => $value2 ], ... ];

my %hash = @$array_ref_of_values;
Только я беру каждый из них и" взрываю " их, разыменовывая ( @$_ ).