如何为key hashmap Perl赋值?

时间:2015-12-07 22:06:29

标签: perl hashmap

我有下面的代码。我想为每个版本值分配但不知何故我不知道我做错了什么。

%buildsMap = ();
#read schedule
opendir (DIR, $buildsDir) or die $!;
while ( my $file = readdir DIR ) {
    if (($file =~ /(V\d\d\d.*)-DVD/) || ($file =~ /(V\d\d\d.*)/)) {
        foreach $version(@versionS){
            if ($1 eq $version ){
               @temp = @{$buildsMap{$version}};
               push @temp,$file;
               @{$buildsMap{$version}} = @temp;
            }
        }
    }
}

如果我想使用此hashmap中的键,则可以。请指教我。

1 个答案:

答案 0 :(得分:3)

第一项业务,开启严格和警告。这将发现任何拼写错误变量和其他错误。这里的主要问题是您必须声明所有变量。修复所有问题并打印出结果%buildMap,我们有一个最小的可行示例。

use strict;
use warnings;
use v5.10;

my $buildsDir = shift;
my @versionS = qw(V111 V222 V333);
my %buildsMap = ();

#read schedule
opendir (DIR, $buildsDir) or die $!;
while ( my $file = readdir DIR ) {
    if (($file =~ /(V\d\d\d.*)-DVD/) || ($file =~ /(V\d\d\d.*)/)) {
        foreach my $version (@versionS) {
            if ($1 eq $version ){
               my @temp = @{$buildsMap{$version}};
               push @temp,$file;
               @{$buildsMap{$version}} = @temp;
            }
        }
    }
}

for my $version (keys %buildsMap) {
    my $files = $buildsMap{$version};

    say "$version @$files";
}

出现错误Can't use an undefined value as an ARRAY reference at test.plx line 15.。这就是这条线。

            my @temp = @{$buildsMap{$version}};

这里的问题是您如何使用数组引用。该特定行失败,因为如果$buildsMap{$version}没有条目,则您尝试取消引用任何内容并且Perl不会允许这样做,而不是正常的取消引用。我们可以解决这个问题,但是有更好的方法来处理列表的哈希。这就是你所拥有的。

           my @temp = @{$buildsMap{$version}};
           push @temp,$file;
           @{$buildsMap{$version}} = @temp;

将所有文件名复制到@temp,使用@temp和更舒适的语法,然后将其复制回来。它对内存和代码量的效率低下。相反,我们可以做到这一点。首先,如果需要,将值初始化为空数组引用,然后直接将文件推送到该数组引用。

            $buildsMap{$version} ||= [];
            push @{$buildsMap{$version}}, $file;

||=or-equals运算符。如果左侧是假的,它只会进行分配。它经常用于设置默认值。你也可以写$buildsMap{$version} = [] if !$buildsMap{$version},但这很快就会变得多余。

但我们甚至不需要这样做! push是一个特例。为方便起见,您可以取消引用空值并将其传递给push!因此,我们不需要初始化程序,只需按下即可。

            push @{$buildsMap{$version}}, $file;

虽然代码有效,但可以提高效率。不是为每个文件名扫描@versionS,如果有很多文件或许多版本,可能会浪费,可能会浪费。现在不需要内循环了。

my %versionS = ( 'V111' => 1, 'V222' => 2, 'V333' => 3 );

...

if (($file =~ /(V\d\d\d.*)-DVD/) || ($file =~ /(V\d\d\d.*)/)) {
    my $version = $1;
    if ($versionS{$version}){
        push @{$buildsMap{$version}}, $file;
    }
}