2012-01-13 57 views
13

我有一個我想排序的數組數組。數組A的每個元素都是一個包含3個元素的數組。 陣列中的樣子:我想在Perl中對數組的數組進行排序,但結果沒有排序

my @A = ([2,3,1], [1,2,3], [1,0,2], [3,1,2], [2,2,4]); 

我想排序按升序排列。比較2個元素時,使用第一個數字。如果有平局,則使用第二個數字,然後使用第三個數字。

這是我的代碼。我使用函數'cmpfunc'來比較2個元素。

sub cmpfunc { 
    return ($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2]); 
} 
my @B = sort cmpfunc @A; 
print "Result:\n"; 
for my $element (@B) { 
    print join(",", @{$element}) . "\n"; 
} 

結果:

1,2,3 
1,0,2 
2,3,1 
2,2,4 
3,1,2 

結果有所排序,而不是正確的。我期望的是:

1,0,2 
1,2,3 
2,2,4 
2,3,1 
3,1,2 

我的比較函數中是否有任何錯誤? 奇怪的是,當我將比較代碼放在塊中時,結果正確排序。

sub cmpfunc { 
    return (($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2])); 
} 
+0

相關:http://stackoverflow.com/questions/1512547 – mob 2012-01-13 15:49:36

回答

21

您正在執行

return ($a->[0] <=> $b->[0]) 

它返回它得到任何 「或」 條款之前:

my @C = sort { ($a->[0] <=> $b->[0]) or 
       ($a->[1] <=> $b->[1]) or 
       ($a->[2] <=> $b->[2]) } @A; 
+8

*或*使用更緊密的綁定或:「||」。 – Axeman 2012-01-13 14:21:58

5

需要更多的括號。

請刪除「返回」的關鍵字,或周圍的整個 ARG列表中添加括號的回報:

sub cmpfunc { 
    return(($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2])); 
} 
9

你觀察這個「錯誤」行爲的原因是or操作,最低的優先級可能。在這種情況下,這意味着

return ($a->[0] <=> $b->[0]) or 
     ($a->[1] <=> $b->[1]) or 
     ($a->[2] <=> $b->[2]); 

被解釋爲的OR-ing

return ($a->[0] <=> $b->[0]) 

與行的其餘部分 - 胡說在這種情況下,作爲回報永遠不會返回。 :)

所以,你應該用C的OR:

return ($a->[0] <=> $b->[0]) || 
     ($a->[1] <=> $b->[1]) || 
     ($a->[2] <=> $b->[2]); 
+1

謝謝,||是一個很好的選擇。 – jftsai 2012-01-13 13:10:14

3
sub cmpfunc { 
    return ($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2]); 
} 

你可以刪除 '回報' 在這裏。

sub cmpfunc { 
    ($a->[0] <=> $b->[0]) or 
    ($a->[1] <=> $b->[1]) or 
    ($a->[2] <=> $b->[2]); 
} 
+0

它仍然會返回評估爲真的第一條語句。 – 2012-01-13 13:20:24

+1

@LeonardoHerrera它應該這樣做。 – TLP 2012-01-13 13:30:52

+0

@TLP - 呃,你是對的。 – 2012-01-13 13:49:57

2

的替代解決方案丹尼爾:

sub cmpfunc { 
    return ($a->[0] <=> $b->[0]) || 
      ($a->[1] <=> $b->[1]) || 
      ($a->[2] <=> $b->[2]); 
} 

or這種情況下的問題是,它具有比分配較低的優先級,讓你的函數只返回($a->[0] <=> $b->[0])的結果,這是-1, 0或1,如果左側數值分別低於,等於或大於右側。||具有更高的優先級,因此整個布爾表達式在返回之前進行評估。如前所述,如果您喜歡||,則可以將表達式放在括號中。我個人不。

+0

實際上,它只返回第一個比較,不管它返回什麼。試試'sub a {return 0或者死掉'Ough'}'。 – TLP 2012-01-13 13:34:11

+0

@TLP:謝謝你指出。 – flesk 2012-01-13 19:01:56