質問

次のコードの結果が表示されますが、次のorの例でsortが何をすべきかを正確に理解していない:

use Data::Dumper;

$animals{'man'}{'name'} = 'paul';
$animals{'man'}{'legs'} = 2;
$animals{'cheeta'}{'name'} = 'mike';
$animals{'cheeta'}{'legs'} = 3;
$animals{'zebra'}{'name'} = 'steve';
$animals{'zebra'}{'legs'} = 4;
$animals{'cat'}{'name'} = '';
$animals{'cat'}{'legs'} = 3;
$animals{'dog'}{'name'} = '';
$animals{'dog'}{'legs'} = 4;
$animals{'rat'}{'name'} = '';
$animals{'rat'}{'legs'} = 5;

@animals = sort {
      $animals{$a}{'name'} cmp $animals{$b}{'name'}
   or $animals{$a}{'legs'} <=> $animals{$b}{'legs'}
} keys %animals;

print Dumper(\@animals);
役に立ちましたか?

解決

orは短絡エバリュエーターであるため、true(ゼロ以外の値)であれば左側の値を返し、そうでない場合は右側を評価します。

したがって、この場合、動物の名前が等しい(0-false)場合、足の数はソートのためにカウントされます。

他のヒント

sortsub({}の後のsortにあるもの)は、2層のソートを定義します:最初に名前で、次にレッグの数で。 orは、2つの基準間のクロスオーバーを実装します。コードの形式を変えた方が見やすいです:

@animals = sort {
    $animals{$a}{'name'} cmp $animals{$b}{'name'} or
    $animals{$a}{'legs'} <=> $animals{$b}{'legs'}
} keys %animals;

cmpおよび<=>演算子は、左の引数が右の引数よりも小さいか、等しいか、大きいかによって3つの値(-1、0、または1)のいずれかを返します。 (<=>は文字列の比較を行い、<=>は数値の比較を行います。)Perlでは、0はfalseで、-1と1はtrueです。 <=>が真の値を返す場合、<=>はすぐにその値を返し、<=>は要素を適切に並べ替えます。 <=>がfalseを返す場合、<=>が評価され、代わりに結果が返されます。

マルチレイヤーソートを行う場合、<!> quot; map-sort-map <!> quot;を使用するのが一般的です。テクニック(a.k.a. シュワルツ変換):

@animals =
  map  { $_->[0] }
  sort {
    $a->[1] cmp $b->[1] ||
    $a->[2] <=> $b->[2]
  }
  map { [$_, $animal{$_}{name}, $animal{$_}{legs}] }
  keys %animal;

それほど明確ではありませんが、通常はパフォーマンスが向上するため、一般的なイディオムです。これは、比較のオペランドが関数である場合に特に重要です。この手法は、比較ごとに不必要な(場合によっては高価な)再計算を防ぎます。たとえば、文字列を長さで並べ替える場合、各文字列の長さを計算する必要があるのは一度だけです。

Sort::Key をお勧めします現在のコード全体の代替物ですか?

use Sort::Key::Multi qw(sikeysort);  # sort keyed on (string, integer)
@animals = sikeysort { $animals{$_}{name}, $animals{$_}{legs} } keys %animals;

# alternately,
use Sort::Key::Maker sort_by_name_then_legs =>
    sub { $animals{$_}{name}, $animals{$_}{legs} }, qw(string integer);
@animals = sort_by_name_then_legs keys %animals;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top