2011-05-23 37 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 
}