Как лучше всего использовать Perl-хэши со значениями массивов? - PullRequest
0 голосов
/ 08 октября 2010

Какая лучшая практика для решения этой проблемы?

    if (... ) 
   { 
    push (@{$hash{'key'}}, @array ) ; 
     }
    else 
     {
     $hash{'key'} =""; 
 }

Это плохая практика для хранения одного элемента - массив или просто двойная кавычка в хэше?

Ответы [ 5 ]

2 голосов
/ 08 октября 2010

Я не уверен, что понимаю ваш вопрос, но я отвечу на него буквально так, как сейчас ...

my @array = (1, 2, 3, 4);
my $arrayRef = \@array;     # alternatively: my $arrayRef = [1, 2, 3, 4];

my %hash;

$hash{'key'} = $arrayRef;   # or again: $hash{'key'} = [1, 2, 3, 4]; or $hash{'key'} = \@array;

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

См. perlref и perlreftut для получения дополнительной информации.

РЕДАКТИРОВАТЬ: Да, вы можете добавить пустые строки в качестве значений для некоторых ключей и ссылок (для массивов или хэшей, или даже скаляры, typeglobs / файловые дескрипторы или другие скаляры. В любом случае) для других ключей.Все они все еще скаляры.

Вы захотите взглянуть на функцию ref, чтобы выяснить, как устранить неоднозначность между ссылочными типами и обычными скалярами.

2 голосов
/ 08 октября 2010

Вероятно, проще использовать явные ссылки на массивы:

my $arr_ref = \@array;
$hash{'key'} = $arr_ref;

На самом деле, выполнение вышеизложенного и использование push приводит к той же структуре данных:

my @array = qw/ one two three four five /;
my $arr_ref = \@array;
my %hash;
my %hash2;
$hash{'key'} = $arr_ref;
print Dumper \%hash;
push @{$hash2{'key'}}, @array;
print Dumper \%hash2;

Это дает:

$VAR1 = {
          'key' => [
                     'one',
                     'two',
                     'three',
                     'four',
                     'five'
                   ]
        };
$VAR1 = {
          'key' => [
                     'one',
                     'two',
                     'three',
                     'four',
                     'five'
                   ]
        };

Использование явных ссылок на массивы использует меньше символов и легче для чтения, чем конструкция push @{$hash{'key'}}, @array, IMO.

Редактировать: Для вашего блока else{}, вероятно, не идеально назначать пустую строку. Было бы намного проще просто пропустить конструкцию if-else и, позже, когда вы обращаетесь к значениям в хэше, выполнить проверку if( defined( $hash{'key'} ) ). Это намного ближе к стандартному языку Perl, и вы не тратите впустую память, храня пустые строки в вашем хэше.

Вместо этого вам придется использовать ref(), чтобы выяснить, какие данные у вас есть в вашем значении, и это менее понятно, чем просто проверка на определенность.

1 голос
/ 08 октября 2010

Я не уверен, какова ваша цель, но есть несколько вещей, которые следует учитывать.

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

 $hash{key} = \@array;  # just a reference

 use Clone; # or a similar module
 $hash{key} = clone( \@array );

Далее, вы хотите добавить к уже существующим значениям, даже если это одно значение?Если вы собираетесь иметь значения массива, я бы сделал все массивы значений, даже если у вас есть один элемент.Тогда вам не нужно решать, что делать, и вы удаляете особый случай:

 $hash{key} = [] unless defined $hash{key};
 push @{ $hash{key} }, @values;

Это может быть ваш ответ «наилучшей практики», который часто убирает столько особых случаев и лишних.логика по возможности.Когда я делаю подобные вещи в модуле, у меня обычно есть метод add_value, который инкапсулирует это волшебство, где мне не нужно его видеть или вводить его более одного раза.

Если у вас уже естьнереферентное значение в хеш-ключе, это тоже легко исправить:

 if( defined $hash{key} and ! ref $hash{key} ) {
      $hash{key} = [ $hash{key} ];
      }

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

 if( defined $hash{key} and ref $hash{key} eq ref {} ) {
      $hash{key} = [ $hash{key} ];
      }
0 голосов
/ 09 октября 2010

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

if ( ... ) { 
    my $r = \$hash{ $key }; # $hash{ $key } autoviv-ed
    $$r   = [] unless ref $$r;
    push @$$r, @values;
}
else { 
    $hash{ $key } = "";
}
  • Я избегаю многократного поиска хешей, сохраняя копию автоматически оживленного слота.
  • Обратите внимание, что код основан на скаляре или массиве, представляющем собой всю вселенную вещей, хранящихся в%hash.
0 голосов
/ 08 октября 2010

Работа с пересмотренным обозначением:

if (... ) 
{ 
    push (@{$hash{'key'}}, @array); 
}
else 
{
    $hash{'key'} = "";
}

мы сразу можем сказать, что вы не следуете стандартному совету, который защищает новичков (и экспертов!) От их собственных ошибок Вы используете символическую ссылку, что не очень хорошая идея.

use strict;
use warnings;

my %hash = ( key => "value" );
my @array = ( 1, "abc", 2 );
my @value = ( 22, 23, 24 );

push(@{$hash{'key'}}, @array);

foreach my $key (sort keys %hash) { print "$key = $hash{$key}\n"; }
foreach my $value (@array)        { print "array $value\n"; }
foreach my $value (@value)        { print "value $value\n"; }

Это не работает:

Can't use string ("value") as an ARRAY ref while "strict refs" in use at xx.pl line 8.

Я не уверен, что смогу понять, чего вы пытались достичь. Даже если вы удалите «используйте строгий»; предупреждение, указанный код не обнаруживает изменения от операции push.

use warnings;

my %hash = ( key => "value" );
my @array = ( 1, "abc", 2 );
my @value = ( 22, 23, 24 );

push @{$hash{'key'}}, @array;

foreach my $key (sort keys %hash)   { print "$key = $hash{$key}\n"; }
foreach my $value (@array)          { print "array $value\n"; }
foreach my $value (@value)          { print "value $value\n"; }
foreach my $value (@{$hash{'key'}}) { print "h_key $value\n"; }

push @value, @array;

foreach my $key (sort keys %hash) { print "$key = $hash{$key}\n"; }
foreach my $value (@array)        { print "array $value\n"; }
foreach my $value (@value)        { print "value $value\n"; }

Выход:

key = value
array 1
array abc
array 2
value 22
value 23
value 24
h_key 1
h_key abc
h_key 2
key = value
array 1
array abc
array 2
value 22
value 23
value 24
value 1
value abc
value 2

Я не уверен, что там происходит.

...