シュワルツ変換を使用できます。
my @sorted = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ $lookup{$_->{bug_severity}, $_ ] }
@unsorted;
説明:
map { [ $lookup{$_->{bug_severity}, $_ ] } @unsorted;
各バグを配列参照にマップします。配列参照の最初の要素は、ルックアップ テーブルからのバグの重大度の数値です。シュワルツ変換を使用すると、 のバグごとに 1 回だけ値を検索します@unsorted。
それで、
sort { $a->[0] <=> $b->[0] }
その配列を最初の要素でソートします。ついに、
@sorted = map { $_->[1] }
によって返された配列から元のバグを引き出しsortます。
getvalハッシュルックアップだけを行っている場合は、実際には必要ありません。
効率的なソーターを自動的に生成するには、CPAN モジュールSort::Makerが優れています。
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 );
出力:
$VAR1 = {
'name' => 'baz',
'bug_severity' => '重大ではない'
};
$VAR1 = {
'名前' => 'フー',
'bug_severity' => '重大'
};
$VAR1 = {
'名前' => 'バー',
'bug_severity' => 'severe'
};
naive メソッドを使用するときに必要なルックアップの数は、 の要素の数に依存することに注意してください@unsorted。簡単なプログラムを使用してそれらを数えることができます。
#!/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";
出力:
C:\Temp> tzt 10
10 個の要素をソートするのに 38 回のルックアップが必要でした
C:\Temp> tzt 100
100 個の要素をソートするのに 978 回のルックアップが必要でした
C:\Temp> tzt 1000
1000 個の要素をソートするのに 10916 回のルックアップが必要でした
C:\Temp> tzt 10000
10000 個の要素をソートするのに 113000 回のルックアップが必要でした
したがって、単純な並べ替えまたはシュワルツ変換の使用が適切な解決策であるかどうかを判断するには、より多くの情報が必要になります。
そして、これは@Etherの議論と一致しているように見える簡単なベンチマークです:
#!/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;
}
});
出力:
C:\Temp> tzt 10
シュワルツのナイーブを評価する
schwartzian 18842/s -- -29%
ナイーブ 26357/s 40% --
C:\Temp> tzt 100
ナイーブ・シュワルツィアンを評価する
ナイーブ 1365/s -- -11%
schwartzian 1532/s 12% --
C:\Temp> tzt 1000
ナイーブ・シュワルツィアンを評価する
ナイーブ 121/s -- -11%
schwartzian 135/s 12% --