2012-08-17 49 views
3

如果$a是阵列数组,则下面的代码有效,但我需要$a作为阵列数组的引用。如何遍历数组作为参考?

问题

我如何通过$a循环?

#!/usr/bin/perl 

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

my @AoA = (['aaa','hdr','500'], 
      ['bbb','jid','424'], 
      ['ccc','rde','402'], 
      ); 

my $a = \@AoA; 

my $s = "bbb"; 
my $d = "ddd"; 

for my $i (0 .. $#a) { 
    for my $j (0 .. $#{ $a[$i] }) { 
     if ($a[$i][$j] eq $s) { 
      $a[$i][$j] = $d; 
      last; 
     } 
    } 
} 

print Dumper $a; 
+2

很好的问题!我其实在想同样的事情。 – cooldood3490 2013-04-05 19:44:09

回答

12
foreach my $row (@$array_ref) { 
    foreach my $cell (@$row) { 
     if ($cell eq $s) { 
      $cell = $d; 
      last; 
     } 
    } 
} 

另外,计算在数组引用元素(正如你可以从上面的代码中发现你并不需要为您的特定代码)的#,最简单的方法是:

my $count = scalar(@$array_ref); 
my $row_count = scalar(@{ $array_ref->[$i] }); 
my $last_index = $#$array_ref; 

此外,要访问arrayrefs的数组引用里面的数据,只需使用引用操作就可以了:

$array_ref->[$i]->[$j]; # The second arrow is optional but I hate omitting it. 

此外,你可以创建你arrayrefs的数组引用你的方式(主动数组的数组的引用),还是向右走作为参考:

my $array_ref = [ 
     [1,2,3] 
     ,[4,5,6] 
     ]; 

作为一个侧面说明,请千万不要用$a$b作为标识符名称 - 它们有特殊用途(例如用于整理块)

+0

'$#$ a'也可以工作并给出最后一个数组索引,这就是在这种情况下所需要的。丑陋?也许吧,但是'标量(@ $ a)'也不完全直观。 – dan1111 2012-08-17 15:26:16

+0

@dan - 是的,我包括$#$操作的完整性。它并不那么难看,但可读性较差,绝对不太有用。我很少必须在Perl中使用C风格循环来实现索引增量。 – DVK 2012-08-17 15:29:04

+1

我同意应避免使用C风格的循环,但对于(0.. $#array){}'通常是有用的。 – dan1111 2012-08-17 16:00:46

0
for my $x (@{$a}) { 
    for (@{$x}) { 
     if ($_ eq $s) { 
      $_ = $d; 
      last; 
     } 
    } 
} 
3

要在Perl中取消引用,您有多种选项。对于初学者,我建议你阅读perlref。以下是相关的代码部分,其中的变更很少,所以您可以看到需要改变的地方(不过,我同意其他人的建议,让您的代码更加完美)。

for my $i (0 .. $#$a) { 
    for my $j (0 .. $#{ $a->[$i] }) { 
     if ($a->[$i][$j] eq $s) { 
      $a->[$i][$j] = $d; 
      last; 
     } 
    } 
} 
1

我发现“last”的用法是模棱两可的,内在的或外在的,所以我将它明确表示出来。

for (@$a) { 
    INNER: 
    for (@$_) { 
     do {$_ = $d; last INNER} if $_ eq $s; 
    } 
} 
1

每当我处理数组或数组的散列或散列或散列数组时,我开始思考面向对象编程。 Perl OOP并不是那么复杂,它隐藏了很多逻辑上的复杂性。

现在,在这个非常简单的例子,这将是一个更容易只是把它写没有面向对象,你已经有几个很好的答案(主要是你忘了提领您参考)。

但是,一旦你开始意识到你可以有更复杂的结构在Perl比简单的哈希表,数组和标量,你的数据结构开始变得更复杂,更难以不OOP解析。

#!/usr/bin/env perl 

use strict; 
use warnings; 
use feature qw(say); 

my $a_of_a = array_of_arrays->new; 

$a_of_a->push(["aaa", "hdr", "500"]); 
$a_of_a->push(["bbb", "jid", "424"]); 
$a_of_a->push(["ccc", "rde", "402"]); 

foreach my $member ($a_of_a->list) { 
    my @array = @{$member}; 
    foreach my $element (@array) { 
     printf "%-5.5s ", $element; 
    } 
    print "\n"; 
} 


package array_of_arrays; 

sub new { 
    my $class = shift; 
    my $self = []; 

    bless $self, $class; 
    return $self; 
} 

sub push { 
    my $self = shift; 
    my $item = shift; 

    push @{$self}, $item; 
    return $self; 
} 

sub pop { 
    my $self = shift; 

    if (scalar @{$self}) { 
     return pop @{$self}; 
    } 
    else { 
     return; 
    } 
} 

sub list { 
    my $self = shift; 
    return @{$self}; 
} 
1

取消引用最简单的方式,在我看来,就是要永远记住,数组和哈希永远只能包含值(见perldoc perldata)。这意味着您的阵列

my @AoA = (['aaa','hdr','500'], 
      ['bbb','jid','424'], 
      ['ccc','rde','402']); 

...只包含三个标量值,它们是对其他数组的引用。你可以写这样的:

my $first = [ qw(aaa hdr 500) ];  # using qw() which will quote the args 
my $sec = [ qw(bbb jid 424) ]; 
my $third = [ qw(ccc rde 402) ]; 
my @all = ($first, $sec, $third); # this array is now identical to @AoA 

考虑到这一点,这是简单的想像一个循环,例如(如DVK在他的回答建议):

for my $aref (@all) { 
    # $aref will contain $first, $sec, and $third 
} 

而且知道$aref是数组引用,解除引用很简单:

for my $aref (@all) { 
    for my $value (@$aref) { 
     # do your processing here 
    } 
} 

此外,由于用于循环在一个的值是混叠的,它们的任何变化将影响原始数组。因此,如果上面的“处理”,在环路含有分配如

$value = $foo; 

这意味着,在@all的值也发生变化,就好像你这样写:

$all[0][1] = $foo;