为什么SORT_REGULAR在PHP中产生不一致的结果?

时间:2013-12-26 22:22:05

标签: php arrays sorting

我正在开发一个类,它使PHP中的数组排序更容易,而且我一直在使用SORT_常量,但是行为或SORT_REGULAR(默认排序类型)似乎根据顺序而不同您添加数组中的项目。而且,我无法看出为什么会出现这种情况的模式。

数组项目

$a = '0.3';
$b = '.5';
$c = '4';
$d = 'F';
$e = 'z';
$f = 4;

情景1:

sort(array($d, $e, $a, $f, $b, $c));

// Produces...
array(6) {
  [0]=>
  string(3) "0.3"
  [1]=>
  string(2) ".5"
  [2]=>
  string(1) "4"
  [3]=>
  string(1) "F"
  [4]=>
  string(1) "z"
  [5]=>
  int(4)
}

情景2:

sort(array($d, $e, $b, $f, $c, $a));

// Produces...
array(6) {
  [0]=>
  string(3) "0.3"
  [1]=>
  string(2) ".5"
  [2]=>
  string(1) "F"
  [3]=>
  string(1) "z"
  [4]=>
  int(4)
  [5]=>
  string(1) "4"
}

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

此行为是“预期的”(或至少已知),因为您对值(字符串和整数)使用不同的类型。请参阅sort()功能手册。

  

警告

     

在对具有混合类型值的数组进行排序时要小心,因为sort()会产生不可预测的结果。

最有可能的是,在排序算法的某个时刻,它将两个值比较为整数而不是字符串。为了避免这种情况,不要尝试对不同类型的数组进行排序(如手册所述)。

答案 1 :(得分:2)

http://php.net/sort

  

警告

     

排序具有混合类型值的数组时要小心,因为sort()   会产生不可预测的结果。

您应该使用其中一个SORT_ *常量。

这里有一些评论:

答案 2 :(得分:1)

SORT_REGULAR与<类似。

似乎SORT_REGULAR遵循与<运算符相同的规则(因此,>运算符)。

在我自己的测试中,对于任何两个值$ v0和$ v1,以下断言确实通过了:

$pair = [$v0, $v1];
sort($pair);
assert($pair[0] < $pair[1]);

对于混合类型,<不是严格的弱序。

不幸的是,<混合使用字符串和整数具有循环行为,并且不具有传递性。因此,它不是Strict weak order

这可以通过以下断言显示,pass

assert('3' < '10');    // Numeric comparison. 2 < 12.
assert('10' < '2 ');  // Lexicographical comparison
// Circular:
assert('2 ' < '3');   // Lexicographical comparison
// Not transitive:
assert(!('3' < '2 '));   // Lexicographical comparison

// And just because it's interesting:
assert('2 ' < 3);    // Numeric comparison. 2 < 3.

排序的想法是,在排序的项目列表中,如果$i < $j,则!($sorted_items[$j] < $sorted_items[$i])

仅当<是严格的总订单或严格的弱订单时才可以这样做。

有时,<会将字符串作为数字读取。

以下规则似乎适用于<

  • 如果两个值都是&#34;看起来像&#34; (*)数字,数字比较适用。
  • 如果一个值 是一个数字,则应用数字比较。
  • 如果两个值都是字符串,并且其中至少有一个看起来不像数字,则应用字母(词典)比较。

(*)字符串&#39; 4&#39; &#34;看起来像&#34;数字4.字符串&#39; 4 x&#39;不是&#34;看起来像&#34;数字4,但(int)'4 x'仍然评估为4。

原始示例

此特定示例中的排序在PHP 7中实际上是一致的,而不是在PHP 5中*,可以看作here

这并不意味着PHP 7可以免受这个问题的影响。在这个具体的例子中恰好可以。

比较各个值reveals

hhvm-3.9.1 - 3.12.0,7.0.0 - 7.1.0alpha2

'0.3' < '.5'
'0.3' < '4'
'0.3' < 'F'
'0.3' < 'z'
'0.3' < 4
'.5' < '4'
'.5' < 'F'
'.5' < 'z'
'.5' < 4
'4' < 'F'
'4' < 'z'
'4' < 4
'F' < 'z'
'F' < 4
'z' < 4

5.5.0 - 5.6.23

'0.3' < '.5'
'0.3' < '4'
'0.3' < 'F'
'0.3' < 'z'
'0.3' < 4
'.5' < '4'
'.5' < 'F'
'.5' < 'z'
'.5' < 4
'4' < 'F'
'4' < 'z'
4 < '4'
'F' < 'z'
'F' < 4
'z' < 4

现在让我们删除无聊的位。

  • &#39; 0.3&#39;比其他任何东西都要小,因此不属于任何一个圈子。
  • &#39; 0.5&#39;小于其他所有东西(在删除&#39; 0.3&#39;之后),因此不属于任何圆圈。

在PHP 7中:

  • &#39; 4&#39;比其他任何东西都要小,因此不属于任何一个圈子。
  • 4比其他任何东西都大,因此不属于任何一个圈子。
  • 'F' < 'z'仍然存在。没有通告。因此,可能只有一种排序顺序:['0.3', '.5', '4', 'F', 'z', 4]

在PHP 5中。*:

有多种方法可以使用这些结果构建圈子。

其中一个圈子是:'4' < 'F''F' < 44 < '4'

这意味着:在任何排序顺序中,至少有两个职位$i$j$i < $j$sorted[$j] < $sorted[$i]