更优雅的访问散列数组的方法

时间:2011-06-21 10:09:23

标签: arrays perl hash perl-data-structures

首先,如果我在即将发布的帖子中得到任何错误的术语,那么这对我来说仍然是一个新的东西。

有些背景,我有一个脚本可以检查我们的归档网络配置,以获取一组特定的设置。因此,该脚本会运行许多检查,并将结果添加到该检查的数组中。

e.g 检查以确保syslog已配置添加到名为@internalsyslogerror

的数组中

运行所有检查后,所有检查的数组都会添加到哈希中,密钥为设备名称。

注意所有代码都使用strict,使用警告

使用以下命令;

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, 
@borderntperror, @borderntperror, @internalntperror, 
@bordertacacserror, @internaltacacserror, @enablepasswordchecks,
@internalsnmpkeyserror, @timezoneerror, @configregistererror, 
@bannererror, @bootregistererror, @domainnameerror];

我所拥有的问题是提取此信息的最优雅方式,我希望减少为了向脚本添加新检查而必须进行的更改量。 目前我必须将附加数组添加到上面的代码中,然后将解除引用部分添加到处理它的子中。

目前我正在做什么来取消引用并输出一个数组然后通过电子邮件发送。

foreach my $k (keys %results) {
    push @results, "<b>$k</b><br>";
    if (defined $results{$k}[0] ){
    push @results, "$results{$k}[0]";
    }
    if (defined $results{$k}[1] ){
    push @results, "$results{$k}[1]";
    }
    if (defined $results{$k}[2] ){
    push @results, "$results{$k}[2]";
    }
    if (defined $results{$k}[3] ){  
    push @results, "$results{$k}[3]";
    }
    if (defined $results{$k}[4] ){
    push @results, "$results{$k}[4]";
    }
    if (defined $results{$k}[5] ){
    push @results, "$results{$k}[5]";
    }
    if (defined $results{$k}[6] ){
    push @results, "$results{$k}[6]";
    }
    if (defined $results{$k}[7] ){
    push @results, "$results{$k}[7]";
    }
    if (defined $results{$k}[8] ){
    push @results, "$results{$k}[8]";
    }
    if (defined $results{$k}[9] ){
    push @results, "$results{$k}[9]";
    }
    if (defined $results{$k}[10] ){
    push @results, "$results{$k}[10]";
    }
    if (defined $results{$k}[11] ){
    push @results, "$results{$k}[11]";
    }
    if (defined $results{$k}[12] ){
    push @results, "$results{$k}[12]";
    }
    if (defined $results{$k}[13] ){
    push @results, "$results{$k}[13]";
    }
}

问题是,我可以做我上面做的事情,但不知何故“动态”生成代码

由于

5 个答案:

答案 0 :(得分:5)

foreach my $k (keys %results) { 
   push @results, "<b>$k</b><br>"; 
   for my $result (@{$results{$k}) {
       next if (!defined $result);
       push @results, $result;
   }
}

甚至

foreach my $k (keys %results) { 
   push @results, "<b>$k</b><br>"; 
   push @results, grep { defined $_ } @{$results{$k}};
}

编辑:在最后一次推送中修正了错误...

答案 1 :(得分:4)

我没有看到足够的代码来确定此代码段不会改变现有行为。但它应该没问题。它肯定会提高可维护性:

foreach my $k (keys %results) {
    push @results, "<b>$k</b><br>";
    foreach my $index ( 0..$#{$results{$k}} ) {
        if (defined $results{$k}[$index] ){
            push @results, "$results{$k}[$index]";
        }
    }
}

以上内容取代了整个foreach / if构造。

答案 2 :(得分:3)

使用for循环:

for ($i = 0; $i < 14; $i++) {
  ...
}

答案 3 :(得分:2)

在我看来,这段代码是......功能失调。如果我错了,请纠正我。

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, ... ];

这只会创建一个标量值的长数组,而不是数组的数组。考虑一下:

C:\perl>perl -we "@a=qw(1 2 3 a); @g=(11,22,33,44); $b{key}=[@a,@g]; print qq(@{$b{key}},\n); print qq($b{key}[0]);"
1 2 3 a 11 22 33 44,
1

这清楚地表明$b{key}包含@a@g的所有值,$b{key}[0]只是引用第一个数组中的第一个值,即{ {1}}。

为了做你正在做的事情,即将日志收集到单独的变量中,在某个键下,你必须使用数组引用:

$a[0]

我能看到您当前解决方案的唯一方法是,如果您的代码中有一个错误/功能(有意或无意),每个数组中的第一个值包含与该类别相关的所有数据,例如:< / p>

$results{$config} = [\@internalsyslogerror, \@bordersyslogerror, ...];

如果是这种情况,那么你所做的就等同于:

$internalsyslogerror[0] = "device A not responding, shutting down.\ndevice A rebooted.\nyada yada\n ....";

但是如果你应该在其中一个阵列中获得两个值,那么你的系统就会被搞砸,你的报告结尾会有一个一个一个错误。除非你使用动态for循环来$results{$config} = [ $internalsyslogerror[0], $bordersyslogerror[0], ...]; 值,否则它仍然会很混乱。

此外,通过排除未定义的值,您的内部结构(仅取决于订单)将被搞砸,这样您就不会知道push中的第一个值是来自@results还是{ {1}}。

结论:

如果您对当前系统运行良好感到满意,只需按照其他人的建议使用for循环。使用动态值而不是绝对值。我喜欢FMc的解决方案(略有改动):

@internalsyslogerror

但是,如果要保留内部结构,则不能排除未定义的值,并且不能将所有不同的数组合并为一个,除非数据已经在第一个数组值中连接了字符串。所以:

@bordersyslogerror

输出的格式也可以微调。而不是字符串连接,例如# Solution by FMc for my $k (keys %results) { push @results, "<b>$k</b><br>"; push @results, grep { defined $results{$k}[$_] } 0 .. $#results{$k}; } ,您可以进行明确的加入:$results{$config} = [ \@array1, \@array2, ...]; .... for my $key (keys %results) { push @results, "<b>$key</b><br>"; my $i=0; for my $ref (@{$results{$key}]) { push @results, "Array $i:\n<br>" . (defined @$ref ? "@$ref" : ""); $i++; } }

答案 4 :(得分:1)

如果您没有对密钥执行任何操作,则这相当于:

@results = map { "$_" } grep {; defined } map { @$_ } values %results;