在PHP中按对象属性对数组进行排序? [英] Sort array by object property in PHP?

查看:118
本文介绍了在PHP中按对象属性对数组进行排序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有这样的对象:

class Person {
  var $age;
  function __construct($age) {
    $this->age = $age;
  }
}

并且我有任何Person s

$person1 = new Person(14);
$person2 = new Person(5);
$people = array($person1, $person2);

是否有一种简单的方法可以通过Person->age属性对$people数组进行排序?

Is there an easy way to sort the $people array by the Person->age property?

推荐答案

问题与使用效率低下有关usort ,因为调用比较回调的开销很大.该答案着眼于使用内置排序功能和非递归快速排序实现之间的区别.

The question was concerned about the inefficiency of using usort because of the overhead of calling the comparison callback. This answer looks at the difference between using the built-in sort functions and a non-recursive quicksort implementation.

随着PHP自2009年以来的发展,答案随着时间的推移而变化,因此我一直在对其进行更新.较旧的资料虽然不再相关,但仍然很有趣!

The answer changed over time as PHP evolved since 2009, so I've kept it updated. The older material, while no longer relevant, is still interesting though!

TL; DR:从php 7.0.1开始,非递归quicksort不再比使用带有回调的usort更快.并非总是如此,这就是为什么详细信息下面进行有趣的阅读.真正的收获是,如果您对问题进行基准测试并尝试其他方法,则可以得出令人惊讶的结果.

TL;DR: as of php 7.0.1, a non-recursive quicksort is no longer faster than using usort with a callback. This wasn't always the case, which is why the details below make interesting reading. The real takeaway is that if you benchmark your problem and try alternative approaches, you can come up with surprising results.

在这里,我们已经发布了php 7.0和7.1.最后,对于该数据集,内置的usort速度非常快!

Well here we are with php 7.0 released and 7.1 on the way! Finally, for this dataset, the built-in usort is ever-so-slightly faster!

+-----------+------------+------------+------------+------------+------------+
| Operation | HHVM       | php7.0.1   | php5.6.3   | 5.4.35     | 5.3.29     |
+-----------+------------+------------+------------+------------+------------+
| usort     | *0.0445    | *0.0139    |  0.1503    |  0.1388    |  0.2390    |
| quicksort |  0.0467    |  0.0140    | *0.0912    | *0.1190    | *0.1854    |
|           | 5% slower  | 1% slower  | 40% faster | 15% faster | 23% faster |
+-----------+------------+------------+------------+------------+------------+

2015年1月更新

当我最初在2009年回答这个问题时,我将使用usort与非递归quicksort进行了比较,以查看是否存在差异.事实证明,两者之间存在显着差异,快速排序的运行速度快了3倍.

Jan 2015 update

When I originally answered this in 2009, I compared using usort with a non-recursive quicksort to see if there was a difference. As it turned out, there was significant difference, with the quicksort running 3x faster.

现在是2015年,我认为重新访问它可能会有用,因此我使用了使用usort和quicksort对15000个对象进行排序的代码,并在3v4l.org上运行了该代码,并在许多不同的PHP版本上运行了该代码.完整的结果在这里: http://3v4l.org/WsEEQ

As it's now 2015, I thought it might be useful to revisit this, so I took code which sorts 15000 objects using usort and quicksort and ran it on 3v4l.org which runs it on lots of different PHP versions. The full results are here: http://3v4l.org/WsEEQ

+-----------+------------+------------+------------+------------+------------+
| Operation | HHVM       | php7alpha1 | php5.6.3   | 5.4.35     | 5.3.29     |
+-----------+------------+------------+------------+------------+------------+
| usort     | *0.0678    |  0.0438    |  0.0934    |  0.1114    |  0.2330    |
| quicksort |  0.0827    | *0.0310    | *0.0709    | *0.0771    | *0.1412    |
|           | 19% slower | 30% faster | 25% faster | 31% faster | 40% faster |
+-----------+------------+------------+------------+------------+------------+

2009年的原始注释

我尝试了 usort ,并在大约1.8秒内对15000个Person对象进行了排序.

Original Notes from 2009

I tried a usort, and sorted 15000 Person objects in around 1.8 seconds.

由于您担心比较函数的调用效率低下,因此我将其与非递归

As you are concerned about the inefficiency of the calls to the comparison function, I compared it with a non-recursive Quicksort implementation. This actually ran in around one third of the time, approx 0.5 seconds.

这是我的代码,对这两种方法进行了基准测试

Here's my code which benchmarks the two approaches

// Non-recurive Quicksort for an array of Person objects
// adapted from http://www.algorithmist.com/index.php/Quicksort_non-recursive.php
function quickSort( &$array )
{
 $cur = 1;
 $stack[1]['l'] = 0;
 $stack[1]['r'] = count($array)-1;

 do
 {
  $l = $stack[$cur]['l'];
  $r = $stack[$cur]['r'];
  $cur--;

  do
  {
   $i = $l;
   $j = $r;
   $tmp = $array[(int)( ($l+$r)/2 )];

   // partion the array in two parts.
   // left from $tmp are with smaller values,
   // right from $tmp are with bigger ones
   do
   {
    while( $array[$i]->age < $tmp->age )
     $i++;

    while( $tmp->age < $array[$j]->age )
     $j--;

    // swap elements from the two sides
    if( $i <= $j)
    {
     $w = $array[$i];
     $array[$i] = $array[$j];
     $array[$j] = $w;

     $i++;
     $j--;
    }

   }while( $i <= $j );

 if( $i < $r )
   {
    $cur++;
    $stack[$cur]['l'] = $i;
    $stack[$cur]['r'] = $r;
   }
   $r = $j;

  }while( $l < $r );

 }while( $cur != 0 );


}


// usort() comparison function for Person objects
function personSort( $a, $b ) {
    return $a->age == $b->age ? 0 : ( $a->age > $b->age ) ? 1 : -1;
}


// simple person object    
class Person {
  var $age;
  function __construct($age) {
    $this->age = $age;
  }
}

//---------test internal usort() on 15000 Person objects------

srand(1);
$people=array();
for ($x=0; $x<15000; $x++)
{
     $people[]=new Person(rand(1,100));
}


$start=microtime(true);
usort( $people, 'personSort' );
$total=microtime(true)-$start;

echo "usort took $total\n";


//---------test custom quicksort on 15000 Person objects------

srand(1);
$people=array();
for ($x=0; $x<15000; $x++)
{
     $people[]=new Person(rand(1,100));
}


$start=microtime(true);
quickSort( $people );
$total=microtime(true)-$start;

echo "quickSort took $total\n";

一个有趣的建议是在类中添加__toString方法并使用sort(),所以我也尝试了该方法.麻烦的是,您必须将SORT_STRING作为第二个参数进行排序,才能使其真正调用magic方法,这具有进行字符串而不是数字排序的副作用.为了解决这个问题,您需要在数字上加上零以使其正确排序.最终结果是,这比usort和自定义的quickSort都要慢

An interesting suggestion was to add a __toString method to the class and use sort(), so I tried that out too. Trouble is, you must pass SORT_STRING as the second parameter to sort get it to actually call the magic method, which has the side effect of doing a string rather than numeric sort. To counter this, you need to pad the numbers with zeroes to make it sort properly. Net result was that this was slower than both usort and the custom quickSort

sort 10000 items took      1.76266698837
usort 10000 items took     1.08757710457
quickSort 10000 items took 0.320873022079

以下是使用__toString()的sort()的代码:

Here's the code for the sort() using __toString():

$size=10000;

class Person {
  var $age;
  function __construct($age) {
    $this->age = $age;
    $this->sortable=sprintf("%03d", $age);
  }


  public function __toString()
  {
     return $this->sortable;
  }
}

srand(1);
$people=array();
for ($x=0; $x<$size; $x++)
{
     $people[]=new Person(rand(1,100));
}


$start=microtime(true);
sort( $people, SORT_STRING);
$total=microtime(true)-$start;

echo "sort($size) took $total\n"

这篇关于在PHP中按对象属性对数组进行排序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆