我有一个我要排序的数组。数组A的每个元素是一个包含3个元素的数组。 数组A看起来像:
my @A = ([2,3,1], [1,2,3], [1,0,2], [3,1,2], [2,2,4]);
我想按升序排序A.比较2个元素时,使用第一个数字。如果存在平局,则使用第二个数字,然后使用第三个数字。
这是我的代码。我使用函数'cmpfunc'来比较2个元素。
sub cmpfunc {
return ($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]);
}
my @B = sort cmpfunc @A;
print "Result:\n";
for my $element (@B) {
print join(",", @{$element}) . "\n";
}
结果:
1,2,3
1,0,2
2,3,1
2,2,4
3,1,2
结果有些分类,但不正确。我的期望是:
1,0,2
1,2,3
2,2,4
2,3,1
3,1,2
我的比较功能有错误吗? 奇怪的是,当我把比较代码放在块中时,结果被正确排序。
my @C = sort { ($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]) } @A;
答案 0 :(得分:21)
您正在执行
return ($a->[0] <=> $b->[0])
在到达任何“或”子句之前返回。
删除“return”关键字,或在整个 arg列表周围添加括号以便返回:
sub cmpfunc {
return(($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]));
}
答案 1 :(得分:9)
您观察到这种“错误”行为的原因是or
运算符的优先级,尽可能低。在这种情况下,这意味着
return ($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]);
被解释为OR-ing
return ($a->[0] <=> $b->[0])
和其余部分 - 在这种情况下是废话,因为return永远不会返回。 :)
所以你应该使用C的OR:
return ($a->[0] <=> $b->[0]) ||
($a->[1] <=> $b->[1]) ||
($a->[2] <=> $b->[2]);
答案 2 :(得分:5)
需要更多括号:
sub cmpfunc {
return (($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]));
}
答案 3 :(得分:3)
sub cmpfunc {
return ($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]);
}
你可以在这里删除'return'。
sub cmpfunc {
($a->[0] <=> $b->[0]) or
($a->[1] <=> $b->[1]) or
($a->[2] <=> $b->[2]);
}
答案 4 :(得分:2)
丹尼尔的另一种解决方案:
sub cmpfunc {
return ($a->[0] <=> $b->[0]) ||
($a->[1] <=> $b->[1]) ||
($a->[2] <=> $b->[2]);
}
or
这种情况的问题是它的优先级低于赋值,所以你的函数只返回($a->[0] <=> $b->[0])
的结果,如果左边是,则返回-1,0或1数值上分别低于,等于或大于右侧。 ||
具有更高的优先级,因此在返回之前会评估整个布尔表达式。如上所述,如果您希望将表达式括在||
中,则可以将表达式括在括号中。我个人没有。