können Sie die Schwartzian Transform verwenden:
my @sorted = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ $lookup{$_->{bug_severity}, $_ ] }
@unsorted;
Erläuterung:
map { [ $lookup{$_->{bug_severity}, $_ ] } @unsorted;
jeden Fehler auf ein Array Referenzkarten, deren erstes Element der numerische Fehler Schwere aus der Lookup-Tabelle. Mit der Schwartzian Transformation, , suchen Sie den Wert nur einmal für jeden Fehler in. Dann
,
sort { $a->[0] <=> $b->[0] }
Sortiervorgänge, die Anordnung durch das erste Element. Schließlich
@sorted = map { $_->[1] }
zieht die ursprünglichen Fehler aus dem Array von sort
zurückgegeben.
Es gibt wirklich keine Notwendigkeit für getval
, wenn alles, was es tut, ein Hash-Lookup ist.
zur automatischen Generierung effizienter Sortierer, Sort::Maker CPAN-Modul ist ausgezeichnet:
use strict; use warnings;
use Sort::Maker;
my @bugs = (
{ name => 'bar', bug_severity => 'severe' },
{ name => 'baz', bug_severity => 'noncritical' },
{ name => 'foo', bug_severity => 'critical' },
);
my $sorter = make_sorter('ST',
name => 'severity_sorter',
init_code => 'my %lookup = (
critical => 0,
severe => 1,
noncritical => -1);',
number => [ code => '$lookup{$_->{bug_severity}}' ],
);
use Data::Dumper;
print Dumper $_ for severity_sorter(@bugs);
Ausgang:
$VAR1 = {
'name' => 'baz',
'bug_severity' => 'noncritical'
};
$VAR1 = {
'name' => 'foo',
'bug_severity' => 'critical'
};
$VAR1 = {
'name' => 'bar',
'bug_severity' => 'severe'
};
Beachten Sie, dass die Anzahl der Abfragen, die gemacht werden müssen, wenn die naive Methode hängt davon ab, die Anzahl der Elemente in @unsorted
. Wir können sie mit dem einfachen Programm zählen:
#!/usr/bin/perl
use strict;
use warnings;
my ($n_elements) = @ARGV;
my @keys = qw(a b c);
my %lookup = map { $keys[$_-1] => $_ } 1 .. @keys;
my @unsorted = map { $keys[rand 3] } 1 .. $n_elements;
my $n_lookups;
my @sorted = sort {
$n_lookups += 2;
$lookup{$a} <=> $lookup{$b}
} @unsorted;
print "It took $n_lookups lookups to sort $n_elements elements\n";
Ausgang:
C:\Temp> tzt 10
It took 38 lookups to sort 10 elements
C:\Temp> tzt 100
It took 978 lookups to sort 100 elements
C:\Temp> tzt 1000
It took 10916 lookups to sort 1000 elements
C:\Temp> tzt 10000
It took 113000 lookups to sort 10000 elements
Daher würde eine weitere Informationen benötigen, um zu entscheiden, ob die naive Art oder mit der Schwartzian Trans die geeignete Lösung ist.
Und hier eine einfache Benchmark ist, die mit @ Ether Argumente zustimmen scheint:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);
my ($n_elements) = @ARGV;
my @keys = qw(foo bar baz);
my %lookup = map { $keys[$_] => $_ } 0 .. $#keys;
my @unsorted = map { {v => $keys[rand 3]} } 1 .. $n_elements;
cmpthese(-1, {
naive => sub {
my @sorted = sort {
$lookup{$a->{v}} <=> $lookup{$b->{v}}
} @unsorted;
},
schwartzian => sub {
my @sorted = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [$lookup{$_->{v}}, $_] }
@unsorted;
}
});
Ausgang:
C:\Temp> tzt 10
Rate schwartzian naive
schwartzian 18842/s -- -29%
naive 26357/s 40% --
C:\Temp> tzt 100
Rate naive schwartzian
naive 1365/s -- -11%
schwartzian 1532/s 12% --
C:\Temp> tzt 1000
Rate naive schwartzian
naive 121/s -- -11%
schwartzian 135/s 12% --
Übrigens, Sie haben kein Array von Hashes, sondern ein Array von Verweisen auf anonyme Hashes. –
Danke, Sinan. Ich habe den Titel korrigiert. –
@ Grahzny: Vielen Dank für eine gute Diskussion. Es war ein ziemlich ruhiger Tag soweit :) – Ether