0

抱歉,如果这已在其他地方解决。我搜索和搜索。

我正在使用一个配置文件,该文件通过左对齐每个块的名称和每个名称的缩进参数来分隔数据块(见__DATA__下文)。我编写了一个脚本,将每个块存储到一个散列中,其中一个$hash{name}键指向一个标量值,一个%hash{args}键指向一个值数组。由于每个块都存储在自己的散列中,因此对散列的引用以匿名方式存储在数组中。最终,我想一一获取这些哈希并处理其中的值,但我在遍历数组时遇到了麻烦。

当我尝试打印存储在每个散列中的值时,它似乎是在列表上下文中获取该数组中的散列引用,因此如果 %hash{args} 是对具有三个元素的数组的引用,那是 foreach 循环的三倍运行。

我如何让该循环中的代码只为我放入该数组的每个哈希引用运行一次?

如果您检查我的输出,很明显嵌套数组引用需要被取消引用,但我一直坚持让循环正确,以至于我还无法解决这个问题。也许解决方案可以解决这两个问题?

看哪:

use strict;
use warnings;

my @array;
my %hash;
my ($name, $args);

while (my $line = <DATA>) {
    chomp($line);        
    if ($line !~ /^\s/) 
    {
        my ($key) = $line =~ /^\S+/g;
        $hash{name} = $key;
        print "Defined a name $key\n";
     } 
     else 
     {
        $line =~ s/^\s+//;
        push (@{ $hash{args} }, $line);
        print "Defined an arg $line\n";
     }
     push (@array, \%hash);
}

foreach my $i (@array)
{
    foreach my $h (keys %{$i}) 
    {
        print $h . "\t";
        print $i->{$h} . "\n";      

    }
}


__DATA__
Sports
    Basketball
    Tennis
    Boxing
Guys
    Tom
    Dick
    Harry

这是输出:

Defined a name Sports
Defined an arg Basketball
Defined an arg Tennis
Defined an arg Boxing
Defined a name Guys
Defined an arg Tom
Defined an arg Dick
Defined an arg Harry
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
args    ARRAY(0x4a8e24)
name    Guys
4

2 回答 2

1

你的问题:

在构建数据结构时,您犯了一些错误:

  • 您总是$key为同一$hash{name}字段分配一个新的。以前的内容被覆盖。最后一个值Guys保持不变。
  • 您将 的引用推%hash@array. 因为引用反映了原始对象的所有变化,所以每次都得到相同的输出。

解决方案:

使用不同的数据结构;-)

您的数据是这样工作的:我们有一组名称,每个名称都带有一个值列表。在 Perl 中,集合是用哈希建模的,所以我们使用一个:

my %hash = ();

每个条目将包含对包含值的数组的引用。最终的数据结构将如下所示:

%hash = (
    Sports => ["Basketball", "Tennis", "Boxing"],
    Guys   => ["Tom", "Dick", "Harry"]
);

您可以使用模块检查当前的数据结构Data::Dumper

use Data::Dumper;
print Dumper (\%name); # has to be given references

要使用此数据结构,只需对您的代码进行最少的改进:

my %hash;
my $key;
while (my $line = <DATA>) {
    chomp $line;        
    if ($line =~ /^(\S+)/) {
        $key = $1;
        $hash{$key} = []; # this is the main difference
        print "Defined a name $key\n";
     } else {
        $line =~ s/^\s+//;
        push @{ $hash{$key} }, $line;
        print "Defined an arg $line\n";
     }
}

我也稍微改变了编码风格,但本质上唯一的区别是我使用名称作为哈希。我记得最后一次$key在循环外使用,以便所有 args 知道该去哪里。

当我想打印数据结构时,each如果名称的顺序不重要,我会使用该函数:

while (my ($name, $arrayRef) = each %hash) {
   my @args = @$arrayRef; # dereference the array
   print qq{name $name with args "@args"\n};
}

或者

while (my ($name, $arrayRef) = each %hash) {
   print "name\t$name\n";
   print "arg\t$_\n" foreach @$arrayRef;
}
于 2012-08-20T23:09:25.320 回答
1

我认为您需要不同的数据结构。试试这个:

use strict;
use warnings;
use Data::Dumper;

my @array;
my %hash;
my ( $name, $args, $key );

while ( my $line = <DATA> ) {
    chomp($line);
    if ( $line !~ /^\s/ ) {
        $key = $line;  #=~ /^\S+/g;
        print "Defined a name $key\n";
    }
    else {
        $line =~ s/^\s+//;
        push (@{$hash{$key}}, $line);
        print "Defined an arg $line\n";
    }
}

print Dumper(\%hash);

__DATA__
Sports
        Basketball
        Tennis
        Boxing
Guys
        Tom
        Dick
        Harry

输出:

$VAR1 = {
          'Sports' => [
                        'Basketball',
                        'Tennis',
                        'Boxing'
                      ],
          'Guys' => [
                      'Tom',
                      'Dick',
                      'Harry'
                    ]
        };

我试图使解决方案接近您自己的代码。

编辑:如果你处理多级数据结构总是用来Data::Dumper转储你的数组/哈希中的确切内容。这将帮助您解决诸如此实例的分配问题。

您的数据结构如下所示:

$VAR1 = [
          {
            'args' => [
                        'Basketball',
                        'Tennis',
                        'Boxing',
                        'Tom',
                        'Dick',
                        'Harry'
                      ],
            'name' => 'Guys'
          },
          $VAR1->[0],
          $VAR1->[0],
          $VAR1->[0],
          $VAR1->[0],
          $VAR1->[0],
          $VAR1->[0],
          $VAR1->[0]
        ];
于 2012-08-20T23:19:29.857 回答