PHP сортировка кажется неисправной - PullRequest
2 голосов
/ 16 марта 2019
### 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) работает нормально.

Чтобы выяснить, почему это произошло, я играл с А в массиве. И я мог видеть, что не только в функции array_multisort, но и в функции 'sort' также запрашивался неверный результат.

Как вы видите, результат rsort выглядит нормально, результат сортировки работает странно, когда дело доходит до 13,16 <14,47 <4,62 <13,29 <15,68 </p>

Кто-нибудь знает, почему это произошло?

// 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 Ответ

1 голос
/ 16 марта 2019

Похоже, вы действительно обнаружили ошибку. Для больших массивов, содержащих NaN значения, представленные константой NAN в PHP, встроенная функция sort завершается ошибкой.

Сравнение с NaN всегда должно приводить к неупорядоченности, как указано kuh-chan в комментариях к вопросу. Однако, как только появляется хотя бы один операнд NaN, в последних версиях PHP (март 2019 г.) оператор космического корабля <=> возвращает 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; }
     );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...