PHP排序似乎出现故障

时间:2019-03-16 05:26:59

标签: php sorting

### Result of sort 

sort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);

{ ...
[51]=> float(11.903327742296) 
[52]=> int(5) 
[53]=> float(13.165002546636) 
[54]=> float(14.478273306964) 
[55]=> float(4.6264742674547) 
[56]=> float(13.290508819344) 
[57]=> float(15.686809055276) } 

### Result or rsort

rsort($keys_arranged, SORT_NUMERIC);
var_dump($keys_arranged);

{
[0]=> float(15.686809055276) 
[1]=> float(14.478273306964) 
[2]=> float(13.290508819344)
[3]=> float(13.165002546636) 
[4]=> float(11.903327742296) 
[5]=> int(5) 
[6]=> float(4.6264742674547)
... }

echo var_export($keys_arranged);

array ( 0 => 3.142678516658294, 1 => 1.0, 2 => 1.0, 3 => 14.478273306963985, 4 => 13.165002546635966, 5 => 1.0, 6 => 1.0005037081114851, 7 => 1.0, 8 => 4.6264742674547001, 9 => 15.686809055275578, 10 => 1.0, 11 => 11.903327742295504, 12 => 13.29050881934397, 13 => 1.0, 14 => 1.0, 15 => 3.5421134937189365, 16 => 1.0, 17 => 0.010999999999999999, 18 => 3.2999566681750605, 19 => 5, 20 => 1.2282984802843129, 21 => 1.0, 22 => 2.9748253120971184, 23 => 0.44855992975075798, 24 => 0.99999999999999989, 25 => 3.8350475954623371, 26 => 1.0625975061426283, 27 => 1.0000072792091179, 28 => 0.99999987785487132, 29 => 1, 30 => 0.0, 31 => 1.0, 32 => 1.0, 33 => 1.0, 34 => 0.0, 35 => 1.0972568578553616, 36 => 1.0, 37 => 1.4077661823957415, 38 => 1.0, 39 => 0.0, 40 => 3.6038030347555705, 41 => 1.0, 42 => 1.0, 43 => 1.0636876768842174, 44 => 1.0, 45 => NAN, 46 => 1.0, 47 => NAN, 48 => NAN, 49 => NAN, 50 => NAN, 51 => 1.0, 52 => 1.0, 53 => NAN, 54 => 0.99958680716631509, 55 => 1.0, 56 => NAN, 57 => 1.0, )

我从array_multisort得到了一些不正确的结果。它有8个不同的键和所有键,但是此键(例如A)可以正常工作。

要弄清楚为什么会发生这种情况,我在数组中使用了A。而且我不仅可以在array_multisort函数中看到,而且在'sort'函数中也可以看到错误的结果。

如您所见,rsort的结果似乎还可以,但sort的结果在 13.16 <14.47 <4.62 <13.29 <15.68

有人知道为什么会这样吗?

// Data in readible format

array (
0 => 3.142678516658294, 
1 => 1.0, 
2 => 1.0, 
3 => 14.478273306963985, 
4 => 13.165002546635966, 
5 => 1.0, 
6 => 1.0005037081114851, 
7 => 1.0, 
8 => 4.6264742674547001, 
9 => 15.686809055275578, 
10 => 1.0, 
11 => 11.903327742295504, 
12 => 13.29050881934397, 
13 => 1.0, 
14 => 1.0, 
15 => 3.5421134937189365, 
16 => 1.0, 
17 => 0.010999999999999999, 
18 => 3.2999566681750605, 
19 => 5, 
20 => 1.2282984802843129, 
21 => 1.0, 
22 => 2.9748253120971184, 
23 => 0.44855992975075798, 
24 => 0.99999999999999989, 
25 => 3.8350475954623371, 
26 => 1.0625975061426283, 
27 => 1.0000072792091179, 
28 => 0.99999987785487132, 
29 => 1, 
30 => 0.0, 
31 => 1.0, 
32 => 1.0, 
33 => 1.0, 
34 => 0.0, 
35 => 1.0972568578553616, 
36 => 1.0, 
37 => 1.4077661823957415, 
38 => 1.0, 
39 => 0.0, 
40 => 3.6038030347555705, 
41 => 1.0, 
42 => 1.0, 
43 => 1.0636876768842174, 
44 => 1.0, 
45 => NAN, 
46 => 1.0, 
47 => NAN, 
48 => NAN, 
49 => NAN, 
50 => NAN, 
51 => 1.0, 
52 => 1.0, 
53 => NAN, 
54 => 0.99958680716631509, 
55 => 1.0, 
56 => NAN, 
57 => 1.0, )

1 个答案:

答案 0 :(得分:1)

似乎您确实发现了一个错误。在包含NaN值的大型数组上(由PHP中的NAN常量表示),内置函数sort失败。

NaN的比较应始终如问题注释中的 kuh-chan 所提到的那样是无序的。但是,一旦存在至少一个操作数NaN,在最新的PHP版本(2019年3月)中,太空飞船操作符<=>返回1 (第一个操作数大于第二个操作数)-1 (第一个操作数小于第二个操作数)

echo var_dump( NAN   <=> 1.23  );
echo var_dump( 1.23  <=> NAN   );
echo var_dump( NAN   <=> -1.23 );
echo var_dump( -1.23 <=> NAN   );
echo var_dump( NAN   <=> 0     );
echo var_dump( NAN   <=> NAN   );

我对Zend引擎的内部并不十分熟悉。但是,我猜想sort算法在具有几个NaN值的大型数组上终止太早了,可能是为了顺序比较算法总是返回“大于(或小于)”,这可能导致多次交换相同的元素。

我经历了多次调用sort似乎可以继续进行排序的过程。但是,那不是一个适当的解决方法。

您可以将自定义比较算法与usort一起使用。如果要在数组的开头对NaN进行排序,则当第一个操作数为-1时返回NaN,当第二个操作数为1时返回NaN 0 (等于)(如果两者都是)。否则,返回航天器运算符的比较结果。

usort($keys_arranged,
  function(&$v1, &$v2)
  {
    switch( (is_nan($v1) ? 1 : 0) | (is_nan($v2) ? 2 : 0) )
    {
      case 0: return $v1 <=> $v2;
      case 1: return -1;
      case 2: return 1;
      case 3: return 0;
    }
  }
);

与上述类似的按位逻辑,但压缩性和直接性更高:

usort( $keys_arranged,
       function(&$v1, &$v2){ return -2 === ($b = (is_nan($v1) ? -1 : -2) ^ (is_nan($v2) ? -1 : 0)) ? $v1 <=> $v2 : $b; }
     );