【问题标题】:Understanding array sorting behavier php了解数组排序行为php
【发布时间】:2013-02-07 14:27:08
【问题描述】:

我有这个数组

$array = array(2, 1, "img1", "img2", "img10", 1.5, "3.14", "2.72");

应用sort函数后就变成了

sort($array);

Array
(
    [0] => 2.72
    [1] => 3.14
    [2] => img1
    [3] => img10
    [4] => img2
    [5] => 1
    [6] => 1.5
    [7] => 2
)

我不明白排序是如何执行的。

谁能解释一下输出数组是怎么实现的?

编辑:

这里的问题不是我应该使用哪个SORT FLAG,而是问题是如何执行上述排序。任何使用另一个SORT FLAG 的建议在这里都是无用的。

【问题讨论】:

  • 设置SORT_NUMERIC标志php.net/sort
  • @Pekka웃:我真的很想知道即使使用SORT_REGULAR 也是如何进行排序的。 SORT_REGULAR 是什么意思?排序规则如何为排序结果中的项目分配优先级?
  • 所以我很确定我已经找到了答案,我会在今晚晚些时候回家时发布它(除非有人打败我)。

标签: php arrays sorting


【解决方案1】:

前两个数字是实际的字符串(您在引号中传递它们),因此它们的处理方式如下:在字母排序中数字位于任何字母之前。

其他的是实数(不带引号),所以函数把它们分开,按数字排序。

array(8)
    0 => '2.72'    [alphabetical]
    1 => '3.14'    [alphabetical]
    2 => 'img1'    [alphabetical]
    3 => 'img10'   [alphabetical]
    4 => 'img2'    [alphabetical]
    5 => 1         [numeric]
    6 => 1.5       [numeric]
    7 => 2         [numeric]

因此,函数必须决定是按字母顺序(a,b,c...)还是按数字顺序(1,2,3..)对元素进行排序,所以它只检查变量类型。

就像 Pekka 指出的那样,可以设置一些标志来强制排序类型。 They are described in the docs.


编辑

这个理论在 cmets 被证明是错误的,我现在完全迷失了(:

文档中的This comment 包含有关此问题的一些有趣观点。

【讨论】:

  • 你能扩展你的答案吗?我真的不明白,如果你能进一步解释,这将是一个很大的帮助。
  • 这不能回答后端使用的比较算法,对我来说这就是问题所在。在预期的结果中,数字将出现在字符串之前。您发现的几乎所有类型都是如此,尤其是由于 ascii 值。为什么php要实现数字排序第二?我检查了文档并运行了一些测试,排序函数不使用标准运算符 (==,)、strcmp()、ord()。有谁知道它在没有标志的 sort() 实现中使用了什么?
  • 我想说的是,它似乎同时使用数字和字母排序,具体取决于您作为参数传递的类型。数字在字母排序中首先出现,但字母排序本身在数字排序之前。
  • 让我告诉你你错了,看看@coanda提供的链接。如果你有机会对这个数组进行排序:("a","b","4",5,4,"true","TRUE",true, false, "c", "d")。然后对这个数组进行排序:("a","b","4",5,4,"true","TRUE",true, false, "c")。这些仅通过删除“d”元素即可返回 2 个完全不同的结果。根据 PHP,这不是错误,而是类型杂耍的结果。
  • 我现在也对混合类型数组的排序算法感到非常困惑,并在这种类型的数组上尝试了各种排序标志。确实需要使用所有排序标志获得实际的排序算法。希望有人会以同样的方式回来
【解决方案2】:

使用 Coanda 链接中的信息作为起点,很明显 PHP 在比较不同类型的对象时使用了类型杂耍。问题是在比较过程中了解什么是什么,我仍然无法找到完整的列表,但总的来说:

string 对比 int 会变成

(int) string <,>,=, (int) int 

在这种情况下,字符串在转换后变为0,因此所有整数都大于字符串。 (预期的)。这是我们需要担心的唯一情况。

PHP 使用快速排序,并且很可能将其枢轴点选为array[n/2],其中 n 是数组中的元素数。知道这两条信息后,我们对上面的数组进行快速排序:

$pivot = $array[n/2] //n is the number of elements, this sets $pivot='img2'
//compare each element in the list (i am going to this by hand for demonstration)

(int) 'img2' < 2 //int to int comparison;'img2' resolves to 0 and 0 < 2
(int) 'img2' < 1 //int to int comparison;'img2' resolves to 0 and 0 < 1
      'img2' > 'img1' // string to string comparison; strcmp is +256 
      'img2' > 'img 10' //string to string comparison; strcmp is +256 
(float) 'img2' < 1.5 //float to float comparison;'img2' resolves to 0 and 0<1.5 
      'img2' > '3.14' //string to string comparison; strcmp is +54
      'img2' > '2.72' //string to string comparison; strcmp is +55

我们现在需要两个新数组(一个代表更大,一个代表小于)。

 $greater = array('img1', 'img10', '3.14', '2.72);
 $less = array(2, 1, 1.5);

现在几乎不需要进一步详细说明,因为我们不小心制作了 2 个数组,其中包含所有易于比较的对象。 $greater 只有字符串,我们可以假设 sort 在这里可以正常工作,并将所有内容都视为字符串。

sort($greater);
var_dump($greater);

产生

array(4) {
  [0]=>
  string(5) "2.72"
  [1]=>
  string(4) "3.14"
  [2]=>
  string(4) "img1"
  [3]=>
  string(5) "img10"
}

这是我们所期望的,也是上面的结果。我们对$lesser做同样的事情

$lesser = array(2, 1, 1.5);
sort($lesser);
var_dump($lesser);

我们得到

array(3) {
  [0]=>
  int(1)
  [1]=>
  float(1.5)
  [2]=>
  int(2)
}

这也是意料之中的。现在,当我们将所有三个数组连接在一起时(为了递归,我将“img2”称为数组)。我们得到了上面的结果。

Array
(
[0] => 2.72
[1] => 3.14
[2] => img1
[3] => img10
[4] => img2
[5] => 1
[6] => 1.5
[7] => 2
)

为了证明这一点,您可以对同一个数组执行相同的过程,但将$arr[3] 换成一个整数。

$arr = array("img2", 1, "img1", 2, "img10", 1.5, "3.14", "2.72");
sort($arr);
var_dump($arr)

给你一个完全不同的结果,因为枢轴从一个字符串变为一个 int 导致浮点字符串被评估为浮点数。

array(8) {
[0]=>
string(4) "img1"
[1]=>
string(5) "img10"
[2]=>
string(4) "img2"
[3]=>
int(1)
[4]=>
float(1.5)
[5]=>
int(2)
[6]=>
string(4) "2.72"
[7]=>
string(4) "3.14"
}

【讨论】:

    【解决方案3】:

    以下错误提供了对混合类型排序的更多见解:https://bugs.php.net/bug.php?id=21728

    引用:

    <?php
    $arr1 = array("a","b","c","d","4",5,4,"true","TRUE",true);
    sort($arr1);
    var_dump($arr1);
    ?>
    
    The output is :
    array(10) {
      [0]=>
      bool(true)
      [1]=>
      int(4)
      [2]=>
      string(1) "4"
      [3]=>
      string(4) "TRUE"
      [4]=>
      string(1) "a"
      [5]=>
      string(1) "b"
      [6]=>
      string(1) "c"
      [7]=>
      string(1) "d"
      [8]=>
      string(4) "true"
      [9]=>
      int(5)
    }
    

    它可能看起来很奇怪 - 为什么 (int)5 是所有字符串之后。这是因为“4”低于(int)5,“4”在“true”之前,“true”在 在 5 之前。前 2 个很明显,第 3 个不明显。但没关系。 最好不要在数组中混合类型。如果将 5 更改为“5”,则 “5”紧跟在“4”之后。

    【讨论】:

    • 当我有混合类型时,我会编写自己的排序函数。函数 usort 使用起来简单有效。见link。我觉得PHP自带的sort函数的结果很难预测。
    猜你喜欢
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多