Perl散列数组值的最佳实践是什么?

时间:2010-10-08 16:19:59

标签: perl hash perl-data-structures

解决此问题的最佳做法是什么?

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

存储一个元素的不良做法是数组还是一个只是哈希的双引号?

5 个答案:

答案 0 :(得分:2)

使用显式数组引用可能更简单:

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 :(得分:2)

我不确定我理解你的问题,但我现在会按照字面意思回答......

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;

问题的症结在于数组或散列采用标量值...因此您需要对数组或散列进行引用并将其用作值。

有关详细信息,请参阅perlrefperlreftut


编辑:是的,您可以添加空字符串作为某些键和引用(对于数组或散列,甚至标量,typeglobs / filehandles或其他标量。无论哪种方式)的值,以用于其他键。他们都还是标量。

您需要查看ref函数,了解如何消除引用类型和普通标量之间的歧义。

答案 2 :(得分:1)

我不确定你的目标是什么,但有几件事需要考虑。

首先,如果要存储数组,是否要存储对原始值的引用或原始值的副本?在任何一种情况下,我都希望避免使用解引用语法并在可以的时候接受引用:

 $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} ];
      }

答案 3 :(得分:0)

处理修订后的表示法:

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.

我不确定我能弄清楚你想要达到的目标。即使你删除'use strict;'警告,显示的代码未检测到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

我不确定那里发生了什么。

答案 4 :(得分:0)

如果您的问题是如何替换之前存储的空字符串值,您可以使用数组推送您的值,这可能是最好的方法:

if ( ... ) { 
    my $r = \$hash{ $key }; # $hash{ $key } autoviv-ed
    $$r   = [] unless ref $$r;
    push @$$r, @values;
}
else { 
    $hash{ $key } = "";
}
  • 我通过保存自动生成的插槽副本来避免多次哈希查找。
  • 请注意,代码依赖于标量或数组,即%hash中存储的整个事物。