2012-01-13 58 views
13

我有一个我想排序的数组数组。数组A的每个元素都是一个包含3个元素的数组。 阵列中的样子:我想在Perl中对数组的数组进行排序,但结果没有排序

my @A = ([2,3,1], [1,2,3], [1,0,2], [3,1,2], [2,2,4]); 

我想排序按升序排列。比较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 

我的比较函数中是否有任何错误? 奇怪的是,当我将比较代码放在块中时,结果正确排序。

sub cmpfunc { 
    return (($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2])); 
} 
+0

相关:http://stackoverflow.com/questions/1512547 – mob 2012-01-13 15:49:36

回答

21

您正在执行

return ($a->[0] <=> $b->[0]) 

它返回它得到任何 “或” 条款之前:

my @C = sort { ($a->[0] <=> $b->[0]) or 
       ($a->[1] <=> $b->[1]) or 
       ($a->[2] <=> $b->[2]) } @A; 
+8

*或*使用更紧密的绑定或:“||”。 – Axeman 2012-01-13 14:21:58

5

需要更多的括号。

请删除“返回”的关键字,或周围的整个 ARG列表中添加括号的回报:

sub cmpfunc { 
    return(($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2])); 
} 
9

你观察这个“错误”行为的原因是or操作,最低的优先级可能。在这种情况下,这意味着

return ($a->[0] <=> $b->[0]) or 
     ($a->[1] <=> $b->[1]) or 
     ($a->[2] <=> $b->[2]); 

被解释为的OR-ing

return ($a->[0] <=> $b->[0]) 

与行的其余部分 - 胡说在这种情况下,作为回报永远不会返回。 :)

所以,你应该用C的OR:

return ($a->[0] <=> $b->[0]) || 
     ($a->[1] <=> $b->[1]) || 
     ($a->[2] <=> $b->[2]); 
+1

谢谢,||是一个很好的选择。 – jftsai 2012-01-13 13:10:14

3
sub cmpfunc { 
    return ($a->[0] <=> $b->[0]) or 
      ($a->[1] <=> $b->[1]) or 
      ($a->[2] <=> $b->[2]); 
} 

你可以删除 '回报' 在这里。

sub cmpfunc { 
    ($a->[0] <=> $b->[0]) or 
    ($a->[1] <=> $b->[1]) or 
    ($a->[2] <=> $b->[2]); 
} 
+0

它仍然会返回评估为真的第一条语句。 – 2012-01-13 13:20:24

+1

@LeonardoHerrera它应该这样做。 – TLP 2012-01-13 13:30:52

+0

@TLP - 呃,你是对的。 – 2012-01-13 13:49:57

2

的替代解决方案丹尼尔:

sub cmpfunc { 
    return ($a->[0] <=> $b->[0]) || 
      ($a->[1] <=> $b->[1]) || 
      ($a->[2] <=> $b->[2]); 
} 

or这种情况下的问题是,它具有比分配较低的优先级,让你的函数只返回($a->[0] <=> $b->[0])的结果,这是-1, 0或1,如果左侧数值分别低于,等于或大于右侧。||具有更高的优先级,因此整个布尔表达式在返回之前进行评估。如前所述,如果您喜欢||,则可以将表达式放在括号中。我个人不。

+0

实际上,它只返回第一个比较,不管它返回什么。试试'sub a {return 0或者死掉'Ough'}'。 – TLP 2012-01-13 13:34:11

+0

@TLP:谢谢你指出。 – flesk 2012-01-13 19:01:56