Как вы сопоставляете массив [key1, val1] с хэшем {key1 => val1} в perl? - PullRequest
4 голосов
/ 04 октября 2011

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

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

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 ]

12 голосов
/ 05 октября 2011

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

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
7 голосов
/ 05 октября 2011
my $ARRAY = [ qw(key1 val1 key2 val2 key3 val3 key4 val4) ];
my $HASH = { @$ARRAY };
4 голосов
/ 05 октября 2011

В примере кода, который вы нашли, часть <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;
3 голосов
/ 05 октября 2011
Я не знал, что вы можете выгрузить массив, и хэш это выяснит.

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

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

%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;
}

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

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.
1 голос
/ 05 октября 2011

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

Этот ответ выглядит так:

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

my %hash = @$array_ref_of_values;

Только я беру каждый из них и "взрываю" их путем разыменования (@$_).

...