您可以使用
Schwartzian Transform:
my @sorted = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ $lookup{$_->{bug_severity}, $_ ] }
@unsorted;
解释:
map { [ $lookup{$_->{bug_severity}, $_ ] } @unsorted;
将每个 bug 映射到一个数组引用,其第一个元素是查找表中的数字 bug 严重性。使用 Schwartzian Transform,你只需要在 @unsorted
中每个 bug 查找一次数值。
然后,
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' => 'noncritical'
};
$VAR1 = {
'name' => 'foo',
'bug_severity' => 'critical'
};
$VAR1 = {
'name' => 'bar',
'bug_severity' => 'severe'
};
请注意,使用简单方法时需要查找的次数取决于@unsorted
中的元素数量。我们可以使用以下简单程序进行计数:
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次查找
因此,人们需要更多的信息来决定是使用朴素排序还是使用Schwartzian变换作为适当的解决方案。
这里有一个简单的基准测试,似乎支持@Ether的观点:
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 naive
schwartzian 18842/s -- -29%
naive 26357/s 40% --
C:\Temp> tzt 100
率 naive schwartzian
naive 1365/s -- -11%
schwartzian 1532/s 12% --
C:\Temp> tzt 1000
率 naive schwartzian
naive 121/s -- -11%
schwartzian 135/s 12% --
whine.pl
的源代码,它似乎是从 SQL 数据库中获取这些内容的。使用适当的SELECT
查询从数据库中获取已经排序好的 bug 不是更好吗? - Sinan Ünür