【问题标题】:Perl: correctly print array of arrays (dereference)Perl:正确打印数组数组(取消引用)
【发布时间】:2012-06-22 10:52:17
【问题描述】:

各位 perl 修道士们,

我仍在思考如何正确取消引用。 (我在发布之前阅读了类似的帖子,但不幸的是,这个概念仍然有点模糊。)

我有以下数组,它内部由两个数组组成。 (顺便说一句,我正在使用严格和警告的编译指示。)

use strict; use warnings;
my @a1; my @a2;

地点:

@a1 = ( "1MB", "2MB", ... )

和..

@a2 = ( "/home", "/home/debug", ... )

@a1 和@a2 都是包含 51 行的数组。所以,我将这些填充到我的第二个数组中。

my @b;
push (@b, [ @a1, @a2 ]);

但是,当我尝试打印@b 的结果时:

sub newl { print "\n"; print "\n"; }
my $an1; my @an1;
$an1 = $#a1;
@an1 = ( 0, 1..$an1 );

for my $i (@an1) { print @b[$i]; &newl; }

我看到了对数组的引用:

ARRAY(0x81c0a10)
  .
ARRAY(0x81c0a50)
  .
  .
  .

如何正确打印此数组?我知道我需要取消对数组的引用,我不知道该怎么做。我尝试这样填充我的数组:

push (@b, [ \@a1, \@a2 ]);

产生相同的结果。我也试过了:

for my $i (@an1) { print @{$b[$i]}; &newl; }

由于数组引用为 0 而导致哪些不幸的错误?

Can't use string ("0") as an ARRAY ref while "strict refs" in use at p_disk_ex6.pl line 42.

非常感谢任何建议!

【问题讨论】:

  • 我还尝试了以下 for 循环:for my $i (@b) { print @{$i}; &newl; } 没有任何运气。我收到相同的错误“在使用“严格引用”时,不能将字符串“0”用作数组引用。我不确定为什么会看到这个错误,为什么 0 被解释为字符串?

标签: arrays for-loop dereference perl


【解决方案1】:

一个简短的示例程序,可能会对您有所帮助:

use strict;
use warnings;

my @a1 = qw(1MB 2MB 10MB 7MB);
my @a2 = qw(/foo /bar /flub /blub);

my @b = (\@a1, \@a2);
# equivalent long version:
# my @b = ();
# $b[0] = \@a1;
# $b[1] = \@a2;

for (my $i = 0; $i <= $#a2; $i++) {
    print "a1[$i]: $b[0][$i]\n";
    print "a2[$i]: $b[1][$i]\n";
    print "\n";
}

在您的示例中,您将一个匿名的 arrayref [] 推入@b。因此 $b[0] 包含数组引用。

my @b;
push (@b, [ \@a1, \@a2 ]);
# this corresponds to:
# $b[0][0] = \@a1;
# $b[0][1] = \@a2;

在您编写 [@a1, @a2] 的示例中,您正在创建一个 array_ref,其中包含连接的数组 @a1 和 @a2(首先是 @a1 的所有元素,然后是 @a2 的所有元素):

my @b;
push(@b , [@a1, @a2]);
# $b[0] = ['1MB' , '2MB', '10Mb', '7MB', '/foo', '/bar', '/flub', '/blub']

【讨论】:

    【解决方案2】:

    即使简单,这也有效

    use strict;
    use warnings;
    
    my @a1 = qw(1MB 2MB 10MB 7MB);
    my @a2 = qw(/foo /bar /flub /blub);
    
    my @b = (@a1, @a2);
    print "@b";
    

    【讨论】:

      【解决方案3】:

      如果您想要一个不假设每个子数组中有多少元素的通用解决方案,并且还允许任意级别的嵌套,那么您最好使用其他人已经编写的包显示递归数据结构。一个特别流行的是 YAML,如果你还没有它,你可以通过运行 cpan 来安装它:

      $ cpan
      Terminal does not support AddHistory.
      
      cpan shell -- CPAN exploration and modules installation (v1.9800)
      Enter 'h' for help.
      
      cpan[1]> install YAML
      

      然后您可以轻松显示任意数据结构。用一个简单的例子来演示:

      use YAML;
      
      my @a1 = qw(1MB 2MB 10MB 7MB);
      my @a2 = qw(/foo /bar /flub /blub);
      
      my @b = (\@a1, \@a2);
      
      print Dump(\@b);
      

      输出结果

      ---
      -
        - 1MB
        - 2MB
        - 10MB
        - 7MB
      -
        - /foo
        - /bar
        - /flub
        - /blub
      

      举个稍微复杂一点的例子

      my @b = (\@a1, \@a2,
               { a => 0, b => 1 } );
      

      给予

      ---
      -
        - 1MB
        - 2MB
        - 10MB
        - 7MB
      -
        - /foo
        - /bar
        - /flub
        - /blub
      - a: 0
        b: 1
      

      要阅读此内容,第 1 列中的三个“-”字符表示包含三个元素的数组。 前两个元素各有四个子元素(第 3 列中带有“-”的行)。这 第三个外部元素是哈希引用,因为它由“键:值”对组成。

      YAML 的一个不错的特性是,您可以使用它将任何递归数据结构转储到文件中,除了那些具有子例程引用的文件,然后稍后使用 Load 将其读回。

      如果你真的必须滚动你自己的显示例程,那当然是可能的,但如果你递归地编写它,你会更容易。您可以使用 ref 检查您的参数是数组引用还是哈希引用(或标量引用):

      my @a1 = qw(1MB 2MB 10MB 7MB);
      my @a2 = qw(/foo /bar /flub /blub);
      
      my @b = (\@a1, \@a2,
               { a => 0, b => 1 } );
      
      print_recursive(\@b);
      print "\n";
      
      sub print_recursive {
          my ($obj) = @_;
      
          if (ref($obj) eq 'ARRAY') {
              print "[ ";
              for (my $i=0; $i < @$obj; $i++) {
                  print_recursive($obj->[$i]);
                  print ", " if $i < $#$obj;
              }
              print " ]";
          }
          elsif (ref($obj) eq 'HASH') {
              print "{ ";
              my @keys = sort keys %$obj;
              for (my $i=0; $i < @keys; $i++) {
                  print "$keys[$i] => ";
                  print_recursive($obj->{$keys[$i]});
                  print ", " if $i < $#keys;
              }
              print " }";
          }
          else {
              print $obj;
          }
      }       
      

      产生输出

      [ [ 1MB, 2MB, 10MB, 7MB ], [ /foo, /bar, /flub, /blub ], { a => 0, b => 1 } ]
      

      我没有写我的示例代码来担心漂亮的打印,也没有 处理标量、子例程或祝福对象引用,但它应该让您了解如何编写一个相当通用的递归数据结构转储器。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-07
        • 1970-01-01
        • 1970-01-01
        • 2019-04-21
        相关资源
        最近更新 更多