首页 文章

如何每个哈希迭代一次数组哈希值,而不是每个嵌套数组元素一次?

提问于
浏览
0

如果这已在其他地方得到解决,请道歉 . 我搜索和搜索 .

我正在使用一个配置文件,通过左对齐每个块的名称和缩进每个名称的参数来分隔数据块(请参阅下面的 __DATA__ ) . 我编写了一个脚本,将每个块存储到散列中,该散列具有指向标量值的 $hash{name} 键,以及指向值数组的 %hash{args} 键 . 由于每个块都存储在自己的哈希中,因此对哈希的引用将匿名存储在数组中 . 最终我在迭代数组时遇到了麻烦 .

当我尝试打印存储在每个哈希中的值时,似乎是在列表上下文中的那个数组中使用哈希引用,所以如果%hash 是对具有三个元素的数组的引用,那么它是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

2 回答

  • 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
    

    Output:

    $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]
            ];
    
  • 1

    你的问题:

    在 Build 数据结构的同时,您犯了一些错误:

    • 您始终将新的 $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;
    }
    

相关问题