【问题标题】:How do I reference a Perl hash in an array in a hash?如何在散列的数组中引用 Perl 散列?
【发布时间】:2010-12-31 21:59:27
【问题描述】:

这是我正在使用的代码 sn-p:

my %photo_details = (
 'black_cat' => (
  ('size' => '1600x1200', 'position' => -25),
  ('size' => '1280x1024', 'position' =>  25),
  ('size' =>   '800x600', 'position' =>   0),
 ),
 'race_car' => (
  ('size' => '1600x1200', 'position' =>  10),
  ('size' =>   '800x600', 'position' =>   5),
 ),
);

my $photo = 'black_cat';

foreach my $photo_detail ($photo_details{$photo})
{
 my $size     = $photo_detail{'size'};
 my $position = $photo_detail{'position'};

 print ("size = $size, position = $position\n");
}

我期望得到的是:

大小 = 1600x1200,位置 = -25

尺寸 = 1280x1024,位置 = 25

尺寸 = 800x600,位置 = 0

我得到的是:

在 C:\Test.pl 第 23 行的连接 (.) 或字符串中使用未初始化的值 $size。

在 C:\Test.pl 第 23 行的连接 (.) 或字符串中使用未初始化的值 $position。

尺寸=,位置=

foreach 语句显然是错误的,因为不仅没有 $size 和 $position 的值,而且它只循环了一次而不是 3 次。我尝试了各种变量前缀的变体,但都没有找到。

我做错了什么?

【问题讨论】:

    标签: arrays perl hash reference perl-data-structures


    【解决方案1】:

    这里是一些更新的代码,解释如下:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my %photo_details = (
        'black_cat' => [
            {'size' => '1600x1200', 'position' => -25},
            {'size' => '1280x1024', 'position' =>  25},
            {'size' =>   '800x600', 'position' =>   0},
        ],
        'race_car' => [
            {'size' => '1600x1200', 'position' =>  10},
            {'size' =>   '800x600', 'position' =>   5},
        ],
    );
    
    
    print Dumper( %photo_details );
    foreach my $name ( keys %photo_details ) {
        foreach my $photo_detail ( @{ $photo_details{$name} } ) {
            my $size     = $photo_detail->{'size'};
            my $position = $photo_detail->{'position'};
    
            print Dumper( $photo_details{$photo} );
    
            print ("size = $size, position = $position\n");
        }
    }
    

    我已经用方括号和大括号替换了一些括号。在 Perl 中,方括号表示对匿名数组的引用,而大括号表示对匿名哈希的引用。这些被称为匿名是因为匿名数组或散列没有明确的变量名。

    由于 Perl 数据结构使您存储对哈希的引用而不是实际的哈希,因此您需要这些来构造引用。您可以分两步执行此操作,如下所示:

    my @array = ( 1, 2, 3 );
    my $array_ref = \@array;
    my %hash = ( 'one' => 1, 'two' => 2, 'three' => 3 );
    my $hash_ref = \%hash_ref;
    

    要从 $array_ref 和 $hash_ref 中获取数据,您需要 -> 运算符:

    print $array_ref->[0], "\n";
    print $hash_ref->{one}, "\n";
    

    在引用哈希键时,您不需要在 {} 中使用引号,尽管有些人认为哈希键上的引号是一种很好的做法。

    我添加了一个迭代整个数据结构的示例作为示例,而不仅仅是查看一个参考。这是第一行:

    foreach my $name ( keys %photo_details ) {
    

    keys 方法返回散列中的所有键,以便您可以按顺序获取它们。下一行遍历 %photo_details 中的所有 photo_detail hashref:

        foreach my $photo_detail ( @{ $photo_details{$photo} } ) {
    

    @{ $photo_details{$photo} } 将引用 $photo_details{$photo} 取消引用到一个数组中,您可以使用 foreach 对其进行迭代。

    我添加的最后一件事是对Data::Dumper 的调用,这是一个随 Perl 分发的非常有用的模块,可以为您打印出数据结构。这在构建这样的数据结构时非常方便,它的近亲 Data::Dumper::Simple 也是如此。不幸的是,这个模块没有随 Perl 一起发布,但我更喜欢它的输出,因为它包含变量名。

    如需进一步了解如何使用引用构建复杂数据结构,请查看perlreftut

    【讨论】:

    • 你不是说$photo_details{$name}吗?
    • my $hash_ref = \%hash_ref; - 应该是\%hash
    • 我这里只有一个问题:我们可以将这个数据结构称为hash of array of hashes 来进行描述吗?
    【解决方案2】:

    首先,每个脚本或模块的开头总是:

    use strict;
    use warnings;
    

    您将收到更多的警告信息并且更快,这对调试有很大帮助。

    我无法复制您的错误:当我将该代码放入一个文件并在没有其他标志的情况下运行它时,我得到:size = , position =你打印的代码中没有$size变量,所以错误信息不匹配。

    但是,您错误地声明了数据结构。哈希和数组可以 只包含标量值,不包含列表:所以如果你想嵌套一个数组或 哈希,您需要将其作为参考。见perldoc perldataperldoc perldscperldoc perlreftut 了解有关数据结构和引用的更多信息。

    my %photo_details = (
        black_cat => [
            { size => '1600x1200', position => -25 },
            { size => '1280x1024', position =>  25 },
            { size => '800x600', position => 0 },
        ],
        race_car => [
            { size => '1600x1200', position =>  10 },
            { size => '800x600', position =>   5 },
        ],  
    );
    
    foreach my $photo_detail (@{$photo_details{black_cat}})
    {
        my $size     = $photo_detail->{size};
        my $position = $photo_detail->{position};
    
        print ("size = $size, position = $position\n");
    }
    

    【讨论】:

    • 我很困惑,$size 在他发布的 sn-p 中肯定 ,你甚至把它带到你的代码中。你什么意思?
    • @lexu:是的,你说得对;我在想错误可能来自使用$photo_detail->{$size}$photo_detail->{size}。我完全忽略了my $size = ... 声明。不过,我不能复制 OP 的错误。启用限制后,代码 barfs 较早,%photo_detail 未声明(由于 for 循环未取消引用数组)。
    • 感谢您的解释。数据结构现在看起来肯定是正确的。但是,如果我尝试上面的代码,我会在第 20 行和第 21 行得到“全局符号“%photo_detail”需要显式包名称”。我阅读了文档(谢谢)并将 foreach 语句更改为[foreach my $photo_detail (@{%photo_details->{black_cat}})], changed [$photo_detail{ size}] 到 [$photo_detail->{size}] and changed [$photo_detail{position}] 到 `[$photo_detail->{position}] 并且它有效,但我在 foreach 行上得到“不推荐使用哈希作为参考”。有什么想法吗?
    • @Ether 我没有弄错你的逻辑,只有 abaut $size 语句让我失望了! OP 似乎正在学习符号和范围的使用.. 起初两者都令人困惑。 (+1 来自我的好建议)
    • @TallGuy:在 'perldoc perlwarn' 中查找该警告消息是有用的:您在 foreach 行上有一个标点符号错误。
    【解决方案3】:

    您真正需要担心的只有一件事,那就是数据结构的顶层。之后,您只需为每个级别使用正确的索引语法:

    如果你有一个常规哈希,你可以访问你想要的键,然后在它之后为每个级别排列附加索引:

     %regular_hash = ...;
     $regular_hash{$key}[$index]{$key2};
    

    如果你有一个引用,你几乎可以做同样的事情,但你必须从顶级引用之后的箭头-> 开始取消引用。之后是相同的索引序列:

     $hash_ref = ...;
     $hash_ref->{$key}[$index]{$key2};
    

    有关所有详细信息,请参阅 Intermediate Perl 我们解释参考语法的地方。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-16
      • 1970-01-01
      • 2016-08-03
      • 2016-09-08
      • 2012-08-03
      • 2014-05-19
      • 2013-05-09
      相关资源
      最近更新 更多