2011-05-23 56 views
2

我不是很擅长Perl,但我需要能够对多维数组进行排序。我一直在玩一些测试代码,试图更好地理解这个概念,并且我认为我越来越接近了,但是我找不到这个魔术组合。我似乎无法正确解引用数组

我似乎无法做的是取消引用我的数组,并让他们打印正确。除了被引用的数组中的值以外,我似乎可以得到关于这些refrences所需的全部信息。

我从制表符分隔的平面文件中获取数据,因此在我的示例代码中,我通过拆分创建多个数组,然后将它们推送到单个数组中来模拟该数据。实际上,我会循环浏览文件,在选项卡上分割并将它们推入阵列中。

如果还有更好的方法可以解决这个问题,那么我就会全神贯注。平面文件中的每一行都是单个记录。我需要先按日期排序才能将最早的记录置顶,然后进行二次排序以按照acct编号对记录进行分组。我在网上查了几个例子,但没有发现任何似乎与我需要模仿的数据一致的东西。所有的

my @s1 = split(/:/, 'X:Y:Z'); 
my @s2 = split(/:/, 'A:B:C'); 
my @s3 = split(/:/, 'Q:L:P:0'); 
my @s4 = split(/:/, 'U:E:G'); 

my @array =(); 
push(@array, \@s1); 
push(@array, \@s2); 
push(@array, \@s3); 
push(@array, \@s4); 

print "@array\n"; 

my @sorted = sort { $a->[0] cmp $b->[0] } @array; 

print "\n"; 
foreach $thingy (@sorted) 
{ 
    print @thingy . "\n"; #result: number 0 
    print $thingy . "\n"; #result: reference 
    #print ${$thingy} . "\n"; #result: 'Not a scalar reference' error 
    print ${@thingy} . "\n"; #result: file name (???) 
    print @{$thingy} . "\n"; #result: length of the array referenced 
} 
+0

不直接关系到你的问题,但你可能要考虑是这样的:'我@array =图[拆分/:/],QW(X:Y:ZA :B:CQ:L:P:0 U:E:G)'。 – FMc 2011-05-23 23:35:47

回答

5

首先,你应该始终把use strict;在程序的顶部。这将尽早发现大量错误。

您的foreach循环中的最后一行是正确取消引用$thingy的最后一行。但由于您已将@{$thingy}放在.(字符串连接)运算符的左侧,因此该数组处于标量上下文中,并且标量上下文中的数组计算其大小。只是说:

print "@{$thingy}\n"; 

得到用空格隔开的@$thingy的元素,或在一般

print join('|', @{$thingy}), "\n"; 

,如果你想使用其他分隔符,如竖线字符。您也可以只说

print @{$thingy}, "\n"; 

打印没有分隔符的元素。

+0

这正是我所需要的。有时,我很难判断Perl是否有趣。它有一些我见过的最疯狂的细微差别。我从来没有想到这是我的问题。谢谢! – MitchelWB 2011-05-24 00:11:56

3

@thingy是未声明和未定义(和不必要的)。

使用两个嵌套循环来

  1. 迭代在你的阵列,阵列引用
  2. 并在随后每次循环迭代所引用数组中的项目。

喜欢这张

foreach my $array_ref (@sorted) 
{ 
    foreach my $item (@{$array_ref}) { 
     print $item, ","; 
    } 
    print "\n"; 
} 

表达@{$array_ref}意愿解除引用的数组引用。那么它就像一个数组一样使用。

增加:

你可以替换

my @s1 = split(/:/, 'X:Y:Z'); 
my @s2 = split(/:/, 'A:B:C'); 
my @s3 = split(/:/, 'Q:L:P:0'); 
my @s4 = split(/:/, 'U:E:G'); 

my @array =(); 
push(@array, \@s1); 
push(@array, \@s2); 
push(@array, \@s3); 
push(@array, \@s4); 

my @array =(); 
push(@array, map { [split(/:/, $_)] } qw(X:Y:Z A:B:C Q:L:P:0 U:E:G)); 

如果分拣需要两个标准(主之一所述第一索引和第二索引处的次级一个)它可以这样写:

my @sorted = sort { $a->[0] cmp $b->[0] 
          || 
        $a->[1] cmp $b->[1] 
        } @array; 
+0

就像我在我原来的文章中所说的那样,这只是我在试图将这段代码插入到我的主脚本之前玩的一个测试脚本。所以在实际的脚本中,所有的数组和推送都将得到更好的处理。我只是抛出脏东西来模仿我的情况,为了清晰起见,我在这里将代码包含在代码片段中。但我也想对主/次排序代码表示感谢。在我的搜索中,我还没有看到任何地方,试图让这种工作。那将是我的下一个挑战,但是你让我变得轻松。我已经测试过它,它的工作原理! – MitchelWB 2011-05-24 00:13:29

2

你需要做的第一件事是添加到您的脚本:

use strict; 
use warnings; 

然后你会得到警告:

Global symbol "@thingy" requires explicit package name 

这意味着@thingy没有定义。在perl中,$thingy@thingy被视为单独的变量。

另一种方式来创建你的阵列是使用匿名数组,像这样:

push @array, [ split(/:/, 'X:Y:Z') ]; 
push @array, [ split(/:/, 'A:B:C') ]; 
... 

然后,你将不必创建一次性变量。或者像一个文件,你形容(\t是标签):

while (<>) { 
    push @array, [ split /\t/, $_ ]; 
} 

的一种方式进行排序多个列,从perlmonks:

my @a = ([1,2], [3,4]); 
my @b = sort { 

    $a->[0] <=> $b->[0] || # the result is -1,0,1 ... 
    $a->[1] <=> $b->[1] # so [1] when [0] is same 

} @a; 

http://www.perlmonks.org/index.pl?node_id=674374

。当然,这是假设数值在你的领域。否则使用cmp

要打印:

for my $ref (@array) { 
    my $i = 0; 
    for my $value (@$ref) { 
     print $value; 
     print "," if ($i++ < $#$ref); # comma delimited 
    } 
    print "\n"; # end of record 
}