【问题标题】:PHP usort() order in case of equality相等情况下的 PHP usort() 顺序
【发布时间】:2012-02-24 21:38:24
【问题描述】:

在 PHP manual for usort() 中,它声明:

如果两个成员比较相等,则它们在排序数组中的相对顺序是未定义的。

还有,

引入了一种新的排序算法。 cmp_function 不保持元素比较相等的原始顺序。

那么我的问题是:如果两个元素相等(例如,用户定义的函数返回 0)会发生什么? 我正在使用这个函数,显然相等的项目在排序后的数组中随机排列。

【问题讨论】:

  • 你的意思是它们在其他相等的值中随机排列吗?当然,它们不会随机插入排序集中的任何位置。
  • 我不明白这个问题......你自己回答了:相等元素的顺序没有定义。
  • 那么如果没有定义,那么数组中相等的元素是通过什么方式排列的呢?这是我不明白的
  • @linkyndy 似乎相等的项目附加在其他相等的项目之后
  • 在我看来也是,我想确定一下。

标签: php sorting


【解决方案1】:

注意不要混淆“未定义”和“随机”。

random 实现确实应该每次都会给出不同的顺序。这意味着当发现结果相等时,有特定的代码可以对结果进行洗牌。这会使算法更复杂、更慢,而且很少会成为理想的结果。

undefined 的意思正好相反:在将算法设计为具有可预测或稳定的顺序时,绝对没有采取任何措施。这意味着每次运行结果可能都不同,如果这恰好是算法对该数据的副作用。

你可以看到the core sort implementation in the PHP source code。它由“快速排序”(分而治之)和插入排序(一种对短列表有效的更简单算法)的混合组成,并带有针对 2、3、4 和 5 个元素的列表的手动优化例程。

因此,平等成员的确切行为将取决于诸如列表大小、这些平等成员在列表中的位置、一批中有多少平等成员等因素。在某些情况下,算法会发现它们是相同的,而不是交换它们(理想情况,因为交换需要时间);在其他情况下,在它们已经相对于其他事物移动之前,它不会直接比较它们,因此它们最终会以不同的顺序结束。

【讨论】:

    【解决方案2】:

    我在sorting 我的array 时也发现了同样的情况,然后我发现了一些自定义函数,因为php 使用定义的sorting 函数有一些限制。

    http://php.net/manual/en/function.uasort.php#Vd114535

    PHP 7 对小数组 (https://bugs.php.net/bug.php?id=53341.

    【讨论】:

      【解决方案3】:

      如果我有一个数组:['b', 'a', 'c', 'b'],并且我要对其进行排序,我会得到:['a','b','b','c']。由于'b' == 'b' php 不能保证一个在另一个之前,所以排序顺序是“未定义”,但是由于它们是相等的,这有关系吗?

      如果您使用的排序函数会为不相等的对象返回 0,那么您将面临完全不同的问题。

      【讨论】:

      • 嗯,我使用usort() 按每个数组中的元素数排序。所以,如果我有0=>(1, 2), 1=>(1, 3), 2=>(1, 2), 3=>(1, 3),则订单变为2=>(1, 2), 1=>(1, 3), 3=>(1, 3), 0=>(1, 2),我想知道为什么最后移动了0
      • 我不确定那个,首先想到的是“看看你的键盘,0 是最后一个”,但这似乎很不相关; ) 多次迭代后的顺序是否相同?如果行为确实“未定义”,则每次都应生成不同的顺序。如果我对排序算法的基本理解是正确的,那么在源数组中移动 0 也会将其移动到结果数组中的另一个位置。
      • 多次迭代后的顺序是一样的,所以即使相等的元素之间也必须有某种排序。我会深入挖掘并发布我的结果。谢谢你的帮助:)
      • 我知道这个问题很老了,但你有没有找到解决这个问题的方法?
      【解决方案4】:

      我也遇到了同样的问题,其中 2 行具有相同的值,当应用排序功能时,它的顺序会发生变化,这是我不想要的。我想根据它们的值对键进行排序,如果它们相等,请不要更改顺序。所以这是我的解决方案-

      // sample array 
      $arr = Array("a" => 0.57,"b" => 1.19,"c" => 0.57,"d" => 0.57,"e" => 0.57,"f" => 0.57,"g" => 0.57,"h" => 0.57,"i" => 0.99,"j" => 1.19,"k" => 1.19);
          $multi_arr = [];
          foreach ($arr as $k=>$val){
             $multi_arr["$val"][] = array($k=>$val); 
          }
          uksort($multi_arr, function ($a, $b) { 
                          return $b > $a ? 1 : -1;
                  });
          $s_arr = [];
          foreach ($multi_arr as $k=>$val){
              foreach($val as $p_id){         
                  $p_arr = array_keys($p_id);
                  $s_arr[] = $p_arr[0]; 
              }
          }
      print_r($s_arr);
      

      输出-

      Array([0] => b,[1] => j,[2] => k,[3] => i,[4] => a,[5] => c,[6] => d,[7] => e,[8] => f,[9] => g,[10] => h)

      【讨论】:

        【解决方案5】:

        如果所有比较的值都相同,php 并不关心顺序。

        例子:

        $temp=array("b"=>"10","c"=>"10","d"=>"10","e"=>"4");

        如上数组有 4 个数组长度,其中 3 个具有相同的值,如图所示 b,c,d = 10; arsort() //arsort()函数对关联数组进行降序排序,根据值进行排序

        如果print_r(arsort($temp)) o/p: => Array ( [b] => 10 [c] => 10 [d] => 10 [e] => 4 )

        这意味着它在排序相等的值后返回数组,但对于相等的值保持位置(顺序)相同

        但是

        如果$temp=array("a"=>"4",b"=>"10","c"=>"10","d"=>"10","e"=>"4"); 在上面的数组 b,c,d = 10 的范围内,两个极左和极右数组的值小于中心 (b,c,d = 10) 值

        上述 temp 的 arsort 是 o/p: Array ( [c] => 10 [b] => 10 [d] => 10 [a] => 4 [e] => 4 )

        它给出了中间部分,即中心的 [c] 数组。 这意味着如果相似的值或相等的值数组从两侧以较低的值数组为界,或者第一个值较低,则相等的顺序会给出三个数组值中的中间一个作为这三个数组中的第一个。

        【讨论】:

          猜你喜欢
          • 2017-06-10
          • 2019-02-01
          • 1970-01-01
          • 2010-10-21
          • 2019-04-08
          • 1970-01-01
          • 2016-01-01
          • 2011-11-09
          • 1970-01-01
          相关资源
          最近更新 更多