Domanda

Vedo i risultati dal seguente codice, ma non capisco esattamente come or sappia cosa fare nell'esempio sort seguente:

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);
È stato utile?

Soluzione

or è un valutatore di cortocircuito, quindi restituirà il valore del lato sinistro se è vero (che è un valore diverso da zero), e altrimenti valuterà il lato destro.

Quindi, in questo caso, se i nomi degli animali sono uguali (0 - false), il numero di gambe verrà conteggiato ai fini dell'ordinamento.

Altri suggerimenti

Il sortsub (l'elemento in {} dopo il sort) definisce un ordinamento a due livelli: prima per nome, poi per numero di segmenti. or implementa il cross-over tra i due criteri. È più facile vedere se si formatta il codice in modo diverso:

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

Gli operatori cmp e <=> restituiscono uno dei tre valori (-1, 0 o 1) a seconda che l'argomento sinistro sia inferiore, uguale o maggiore dell'argomento destro. (<=> esegue un confronto di stringhe, <=> esegue un confronto numerico.) In Perl, 0 è falso mentre -1 e 1 sono vere. Se <=> restituisce un valore vero, <=> restituisce immediatamente quel valore e <=> riordina gli elementi in modo appropriato. Se <=> restituisce false, viene valutato <=> e viene invece restituito il risultato.

Quando si eseguono ordinamenti multistrato, è comune utilizzare un " map-sort-map " tecnica (a.k.a. Schwartzian Transform ):

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

Non è così chiaro ma perché di solito ha prestazioni migliori è un linguaggio comune. Ciò è particolarmente importante quando gli operandi per il confronto sono funzioni: questa tecnica impedisce un ricalcolo non necessario (e forse costoso) per ogni confronto. Ad esempio, se stai ordinando le stringhe per lunghezza devi solo calcolare la lunghezza di ogni stringa una volta.

Posso suggerire Sort::Key come un'alternativa al presente codice del tutto?

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top