[英]How do I sort an array of hash references by one of the hash values?
首先,请原谅我生锈的 Perl。 我正在尝试修改 Bugzilla 的“whine.pl”以生成按严重性排序的错误列表。
所以它给了我一个哈希引用数组。 每个哈希都包含有关特定错误(ID、受让人、严重性等)的一堆信息。 我想按严重性对数组进行排序。 做到这一点的最佳方法是什么?
我想出了几种可能性。 一种是创建五个数组(每个严重性级别一个),然后遍历数组并将散列引用推送到适当的严重性级别数组中。 在此之后,我可以重新组装它们并用排序后的数组替换原始数组。
我的朋友想出的另一种方法是将严重性级别(存储为散列中的文本)分配给一些数字,然后对它们进行压缩。 也许是这样的?
sub getVal {
my $entry = $_[0];
%lookup = ( "critical" => 0, ... );
return $lookup(entry("bug_severity"));
}
@sorted = sort { getVal($a) <=> getVal($b) } @unsorted;
为了避免多次调用 getVal,您可以使用“装饰、排序、取消装饰”。 Decorate 正在获取您真正关心的信息:
my @decorated = map { [ $_, getVal($_) ] } @unsorted;
然后对装饰列表进行排序:
my @sortedDecorate = sort { $a->[1] <=> $b->[1] } @decorated;
然后取回原始信息(未修饰):
my @sorted = map { $_->[0] } @sortedDecorate;
或者更像 Perl 的方式来做到这一点:
@sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, getVal($_) ] } @unsorted;
您可以使用施瓦兹变换:
my @sorted = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [ $lookup{$_->{bug_severity}, $_ ] }
@unsorted;
解释:
map { [ $lookup{$_->{bug_severity}, $_ ] } @unsorted;
将每个错误映射到一个数组引用,其第一个元素是查找表中的数字错误严重性。 使用 Schwartzian 变换,您只需为@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' => 'noncritical' }; $VAR1 = { 'name' => 'foo', 'bug_severity' => 'critical' }; $VAR1 = { 'name' => 'bar', 'bug_severity' => 'severe' };
请注意,使用 naive 方法时需要进行的查找次数取决于@unsorted
的元素@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 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
因此,需要更多信息来决定朴素排序还是使用 Schwartzian 变换是合适的解决方案。
这是一个简单的基准测试,它似乎与@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 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% --
我喜欢你提出的解决方案:
my %sevs = (critical => 0, high => 1, ...);
my @sorted = sort { $sevs{$a->{bug_severity}} <=> $sevs{$b->{bug_severity}} } @unsorted
您可以使用查找表来确定 bugzilla 严重性的顺序,如下所示(使用示例数据进行说明):
use strict; use warnings;
use Data::Dumper;
my @bugInfo = (
{ id => 1,
assignee => 'Bob',
severity => 'HIGH'
},
{ id => 2,
assignee => 'Anna',
severity => 'LOW'
},
{ id => 3,
assignee => 'Carl',
severity => 'EXTREME'
},
);
my %severity_ordering = (
EXTREME => 0,
HIGH => 1,
MEDIUM => 2,
LOW => 3,
);
sub byseverity
{
$severity_ordering{$a->{severity}} <=> $severity_ordering{$b->{severity}}
}
my @sortedBugs = sort byseverity @bugInfo;
print Dumper(\@sortedBugs);
产量:
$VAR1 = [
{
'assignee' => 'Carl',
'id' => 3,
'severity' => 'EXTREME'
},
{
'assignee' => 'Bob',
'id' => 1,
'severity' => 'HIGH'
},
{
'assignee' => 'Anna',
'id' => 2,
'severity' => 'LOW'
}
];
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.