与此问题类似:sort by subset of perl string
我想首先按值排序,然后按键的子集排序。
我的%哈希
cat_02 => 0
cat_04 => 1
cat_03 => 0
cat_01 => 3
输出:(可以是按此顺序的键数组)
cat_02 => 0
cat_03 => 0
cat_04 => 1
cat_01 => 3
奖励:关键的二级比较会识别1234_2_C01且小于1234_34_C01(cmp不会)
答案 0 :(得分:8)
my %hash = (
cat_02 => 0,
cat_04 => 1,
cat_03 => 0,
cat_01 => 3
);
print "$_ => $hash{$_}\n"
for sort { $hash{$a} <=> $hash{$b} or $a cmp $b } keys %hash;
排序对值进行数值比较,如果它们相等,则执行or
之后的部分,它会对键进行字符串比较。这会给出您要求的输出。
对于包含与非数字内容混合的数字的字符串的智能排序,请从http://www.davekoelle.com/alphanum.html获取字母比较函数,并将$a cmp $b
替换为alphanum($a,$b)
答案 1 :(得分:4)
使用Sort :: Key :: modules:
可以轻松完成(快速!)use Sort::Key::Natural qw( );
use Sort::Key::Maker intnatkeysort => qw( integer natural );
my @sorted_keys = intnatkeysort { $hash{$_}, $_ } keys(%hash);
或者您可以利用数据的属性并使用自然类型:
use Sort::Key::Natural qw( natkeysort );
my @sorted_keys = natkeysort { "$hash{$_}-$_" } keys(%hash);
答案 2 :(得分:3)
如果您有辅助排序首选项,只需在排序例程中添加另一个级别:
my %hash = (
cat_02 => 0,
cat_04 => 1,
cat_03 => 0,
cat_01 => 3
);
my @sorted = sort { $hash{$a} <=> $hash{$b} || $a cmp $b } keys %hash;
# primary sort method ^^ secondary sort method
for (@sorted) {
print "$_\t=> $hash{$_}\n";
}
<强>输出:强>
cat_02 => 0
cat_03 => 0
cat_04 => 1
cat_01 => 3
答案 3 :(得分:1)
在这种特殊情况下可能不值得,但Schwartzian transform技术也可用于多标准排序。像这样(codepad):
use warnings;
use strict;
my %myhash = (
cat_2 => 0, cat_04 => 1,
cat_03 => 0, dog_02 => 3,
cat_10 => 0, cat_01 => 3,
);
my @sorted =
map { [$_->[0], $myhash{$_->[0]}] }
sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
map { m/([0-9]+)$/ && [$_, $myhash{$_}, $1] }
keys %myhash;
print $_->[0] . ' => ' . $_->[1] . "\n" for @sorted;
显然,这种技术的关键是在缓存中使用多个附加元素。
这里有两件事:1)@sorted
实际上变成了数组的数组(这个数组的每个元素都是键值对); 2)此示例中的排序基于键的数字后缀(使用数字,而不是字符串比较),但如果需要,可以在任何方向上进行调整。
例如,当密钥匹配模式XXX_DD_XXX(以及应该比较的DD)时,请使用以下内容更改第二个map
子句:
map { m/_([0-9]+)_/ && [$_, $myhash{$_}, $1] }