我看到以下代码的结果,但我不明白or
如何知道在以下sort
示例中该怎么做:
use Data::Dumper;
$animals{'man'}{'name'} = 'paul';
$animals{'man'}{'legs'} = 2;
$animals{'cheeta'}{'name'} = 'mike';
$animals{'cheeta'}{'legs'} = 3;
$animals{'zebra'}{'name'} = 'steve';
$animals{'zebra'}{'legs'} = 4;
$animals{'cat'}{'name'} = '';
$animals{'cat'}{'legs'} = 3;
$animals{'dog'}{'name'} = '';
$animals{'dog'}{'legs'} = 4;
$animals{'rat'}{'name'} = '';
$animals{'rat'}{'legs'} = 5;
@animals = sort {
$animals{$a}{'name'} cmp $animals{$b}{'name'}
or $animals{$a}{'legs'} <=> $animals{$b}{'legs'}
} keys %animals;
print Dumper(\@animals);
答案 0 :(得分:14)
sortsub({}
之后的sort
中的内容)定义了两层排序:首先是名称,然后是腿数。 or
实现了两个标准之间的交叉。您可以更轻松地查看是否以不同方式格式化代码:
@animals = sort {
$animals{$a}{'name'} cmp $animals{$b}{'name'} or
$animals{$a}{'legs'} <=> $animals{$b}{'legs'}
} keys %animals;
cmp
和<=>
运算符返回三个值(-1,0或1)中的一个,具体取决于左参数是小于,等于还是大于右参数。 (cmp
进行字符串比较,<=>
进行数字式比较。)在Perl中,0为假,而-1和1为真。如果cmp
返回true值,则or
会立即返回该值,sort
会相应地重新排序这些元素。如果cmp
返回false,则会评估<=>
并返回其结果。
在进行多层排序时,通常使用“map-sort-map”技术(a.k.a。Schwartzian Transform):
@animals =
map { $_->[0] }
sort {
$a->[1] cmp $b->[1] ||
$a->[2] <=> $b->[2]
}
map { [$_, $animal{$_}{name}, $animal{$_}{legs}] }
keys %animal;
它不是那么清楚,但因为它通常具有更好的性能,所以它是一种常见的习语。当比较的操作数是函数时,这一点尤其重要 - 这种技术可以防止每次比较的不必要(并且可能是昂贵的)重新计算。例如,如果您按长度排序字符串,则只需计算一次字符串的长度。
答案 1 :(得分:9)
or
是一个短路评估器,如果它是真的(它是任何非零值)它将返回左侧的值,否则将评估右侧。
因此,在这种情况下,如果动物的名字相等,(0 - 假),腿数将被计算用于分类目的。
答案 2 :(得分:2)
我可以建议Sort::Key
作为现有代码的替代方案吗?
use Sort::Key::Multi qw(sikeysort); # sort keyed on (string, integer)
@animals = sikeysort { $animals{$_}{name}, $animals{$_}{legs} } keys %animals;
# alternately,
use Sort::Key::Maker sort_by_name_then_legs =>
sub { $animals{$_}{name}, $animals{$_}{legs} }, qw(string integer);
@animals = sort_by_name_then_legs keys %animals;