2012-01-13 8 views
13

私は並べ替える配列の配列を持っている。配列Aの各要素は、3つの要素を持つ配列です。私はPerlで配列の配列をソートしたいが、結果はソートされていない。

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

Iが昇順にソートしたい: アレイAは次のようになります。 2つの要素を比較すると、最初の数値が使用されます。同数の場合は、2番目の番号が使用され、3番目の番号が使用されます。

ここに私のコードです。私は関数 '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 

比較機能にエラーがありますか? 奇妙なことは、比較コードをブロックに入れると、結果が正しくソートされることです。あなたはそれが "または" 条項のいずれかになる前に戻ります

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

を実行している

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

関連:http://stackoverflow.com/questions/1512547 – mob

答えて

21

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

*または*厳密なバインディングまたは:||を使用してください。ありがとうございます、|| – Axeman

5

は、より多くの括弧を必要とします。

どちらの「リターン」のキーワードを削除するか、復帰のための全体引数リストの周りに括弧を追加します。

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]); 

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

と、行の残りの部分として解釈OR-INGのしていることを意味しますあなたはここに 'リターン' を削除することができ

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

良い選択肢です。 – jftsai

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

::)

だから、CのORを使用する必要があります。

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

それでもtrueを評価する最初のステートメントが返されます。 –

+1

@LeonardoHerreraそれはやるべきことです。 – TLP

+0

@TLP - doh、そうです。 –

2

ダニエルの代替ソリューション:

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

orこの場合の問題は、それはそう、あなたの関数が唯一-1である($a->[0] <=> $b->[0])の結果を返し、割り当てよりも低い優先順位を持っているということです、左辺が右辺よりも数値的に小さい、等しい、または大きい場合は0または1になります。||の方が優先度が高いため、ブール式全体が返される前に評価されます。前述のように、もしあなたが||を望むならば、式をカッコで囲むことができます。私は個人的にはしません。

+0

実際には、返されたものにかかわらず、最初の比較のみを返します。 'sub a {return 0 or die" Ough "}"を試してください。 – TLP

+0

@TLP:それを指摘してくれてありがとう。 – flesk