按PHP中的对象属性排序数组?

时间:2022-01-19 20:21:23

If I have an object as such:

如果我有这样的对象:

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

and I have any array of Persons

我有各种各样的人

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

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

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

15 个解决方案

#1


87  

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.

问题是由于调用比较回调的开销而导致使用usort的效率低下。这个答案考察了使用内置排序函数和非递归快速排序实现之间的区别。

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!

随着PHP自2009年以来的发展,答案随着时间的推移而改变,所以我一直更新它。旧材料,虽然不再相关,仍然是有趣的!

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.1,非递归快速排序并不比使用usort进行回调要快。情况并非总是如此,这就是为什么下面的细节值得一读。真正重要的是,如果你衡量你的问题并尝试其他的方法,你会得到令人惊讶的结果。

Jan 2016 update

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!

现在我们发布了php 7.0和7.1。最后,对于这个数据集,内置的usort总是非常快!

+-----------+------------+------------+------------+------------+------------+
| 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 |
+-----------+------------+------------+------------+------------+------------+

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.

当我在2009年回答这个问题时,我比较了使用usort和非递归快速排序,看看是否有区别。结果显示,快速排序的运行速度比原来快了3倍。

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

因为现在是2015年,所以我认为有必要重新讨论这个问题,所以我使用usort和quicksort对15000个对象进行排序,并在3v4l.org上运行,在很多不同的PHP版本上运行。完整的结果如下: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 |
+-----------+------------+------------+------------+------------+------------+

Original Notes from 2009

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

我尝试了usort,在1.8秒内对15000件物品进行了排序。

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.

当您担心对比较函数的调用效率低下时,我将它与非递归快速排序实现进行了比较。这段时间大约是1 / 3,大约是0。5秒。

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";

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

一个有趣的建议是向类中添加__toString方法并使用sort(),所以我也尝试过了。麻烦的是,必须将SORT_STRING作为第二个参数进行排序,以使其实际调用魔术方法,这具有执行字符串而不是数字排序的副作用。为了解决这个问题,您需要用0填充数字以使其正确排序。最终的结果是,这比usort和自定义快速排序都要慢

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

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

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

$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"

#2


41  

For that specific scenario, you can sort it using the usort() function, where you define your own function to compare the items in the array.

对于特定的场景,可以使用usort()函数对其进行排序,其中定义自己的函数来比较数组中的项。

<?php

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

function personSort( $a, $b ) {
    return $a->age == $b->age ? 0 : ( $a->age > $b->age ) ? 1 : -1;
}

$person1 = new Person(14);
$person2 = new Person(5);
$person3 = new Person(32);
$person4 = new Person(150);
$person5 = new Person(39);
$people = array($person1, $person2, $person3, $person4, $person5);

print_r( $people );

usort( $people, 'personSort' );

print_r( $people );

#3


10  

You could either use usort or a heap.

您可以使用usort或heap。

 class SortPeopleByAge extends SplMaxHeap
  {
      function compare($person1, $person2)
      {
          return $person1->age - $person2->age;
      }
  }

  $people = array(new Person(30), new Person(22), new Person(40));  
  $sorter = new SortPeopleByAge;
  array_map(array($sorter, 'insert'), $people);
  print_r(iterator_to_array($sorter)); // people sorted from 40 to 22

Note that the purpose of an Heap is to have an ordered collection at all times and not to replace usort. For large collections (1000+), a heap will be faster and less memory intensive though.

注意,堆的目的是始终拥有有序的集合,而不是替换usort。对于大型集合(1000+),堆速度更快,内存占用更少。

An added benefit of having Heaps is being able to use their comparison function for callbacks to other sorting functions, like usort. You just have to remember that the order for the comparison is reversed, so any comparison done with a Heap will result in reversed order in usort.

拥有堆的另一个好处是可以将它们的比较函数用于对其他排序函数(如usort)的回调。您只需要记住,比较的顺序是颠倒的,因此任何与堆的比较都将导致usort中的反向顺序。

// using $people array and $sorter
usort($people, array($sorter, 'compare'));
print_r($people); // people sorted from 22 to 40

usort is fine for small to medium collections where you will do the sorting once at the end. Of course, you dont have to have a heap to use usort. You can just as well add any other valid callback for the sorting.

usort对于中、小型的收藏都很合适,最后进行一次排序。当然,使用usort不需要有堆。您也可以为排序添加任何其他有效的回调。

#4


7  

I just coded this. It should be faster than usort as it does not rely on numerous function calls.

我只是编码。它应该比usort更快,因为它不依赖于大量的函数调用。

function sortByProp($array, $propName, $reverse = false)
{
    $sorted = [];

    foreach ($array as $item)
    {
        $sorted[$item->$propName][] = $item;
    }

    if ($reverse) krsort($sorted); else ksort($sorted);
    $result = [];

    foreach ($sorted as $subArray) foreach ($subArray as $item)
    {
        $result[] = $item;
    }

    return $result;
}

Usage:

用法:

$sorted = sortByProp($people, 'age');

Oh, and it uses ksort but it works even if many $people are of the same $age.

哦,它使用ksort,但它能工作,即使很多人都是相同的年龄。

#5


5  

You just need to write a custom comparison function, then use something like usort to do the actual sorting. For example, if the member variable was myVar, you could sort it as follows:

您只需编写一个自定义比较函数,然后使用usort这样的代码进行实际排序。例如,如果成员变量是myVar,您可以将其排序如下:

function cmp($a, $b)
{
    if ($a->myVar == $b->myVar) {
        return 0;
    }
    return ($a->myVar < $b->myVar) ? -1 : 1;
}

usort($myArray, "cmp");

#6


2  

I do not advice my solution in your example because it would be ugly (And I have not benchmarked it), but it works.... And depending of the need, it may help. :)

我不建议我的解决方案在你的例子,因为它丑(和我没有标准的),但它的工作原理....根据需要,它可能会有所帮助。:)

class Person
{
  public $age;

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

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

$person1 = new Person(14);
$person2 = new Person(5);

$persons = array($person1, $person2);
asort($persons);

#7


2  

Here’s a stable Radix Sort implementation for values 0...256:

下面是一个稳定的基数排序实现,其值为0…256:

function radixsort(&$a)
{
    $n = count($a);
    $partition = array();
    for ($slot = 0; $slot < 256; ++$slot) {
        $partition[] = array();
    }
    for ($i = 0; $i < $n; ++$i) {
        $partition[$a[$i]->age & 0xFF][] = &$a[$i];
    } 
    $i = 0;
    for ($slot = 0; $slot < 256; ++$slot) {
        for ($j = 0, $n = count($partition[$slot]); $j < $n; ++$j) {
            $a[$i++] = &$partition[$slot][$j];
        }
    }
}

This costs only O(n) since Radix Sort is a non-comparing sorting algorithm.

这只需花费O(n),因为基数排序是一种非比较排序算法。

#8


2  

One observation is that if the source of the data is from a database, it's probably faster to sort using SQL than it would be within PHP. Of course this is moot if the data source is from a CSV or XML file.

一种观察是,如果数据源来自数据库,那么使用SQL进行排序的速度可能比在PHP中要快。当然,如果数据源来自CSV或XML文件,这是没有意义的。

#9


2  

I went with the following approach: created a function that takes an array of objects, then inside the function I create an associative array using the property as key for the array, then sort they array keys using ksort:

我采用以下方法:创建一个接受对象数组的函数,然后在函数中使用属性作为数组的键,创建一个关联数组,然后使用ksort对它们的数组键进行排序:

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

function sortPerson($persons = Array()){
    foreach($persons as $person){
        $sorted[$person->age] = $person;
    }
    ksort($sorted);
    return array_values($sorted);
}

$person1 = new Person(14);
$person2 = new Person(5);

$persons = array($person1, $person2);
$person = sortPerson($persons);

echo $person[0]->age."\n".$person[1]->age;
/* Output:
5
14
*/

#10


2  

You can do it with ouzo goodies:

你可以用茴香香料来做:

$result = Arrays::sort(array($person1, $person2), Comparator::compareBy('age'));

http://ouzo.readthedocs.org/en/latest/utils/comparators.html

http://ouzo.readthedocs.org/en/latest/utils/comparators.html

#11


1  

usort() or uasort() /* to maintain index association if you were using an associative array */

如果使用关联数组*/,则使用usort()或uasort() /* *来维护索引关联

#12


1  

Yes. If you implement spl ArrayObject in your person object, all the normal php array functions will work properly with it.

是的。如果您在person对象中实现了spl ArrayObject,那么所有正常的php数组函数都可以正常工作。

#13


1  

Try usort: http://www.php.net/manual/en/function.usort.php

试的作用:http://www.php.net/manual/en/function.usort.php

Example:

例子:

<?php
function cmp($obja, $objb)
{
    $a = $obja->sortField;
    $b = $objb->sortField;
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array( /* your objects */ );

usort($a, "cmp");

?>

#14


1  

If all member variables in question are guaranteed to be different, it will be simpler and faster to create a new collection indexed by these values and then ksort it:

如果所有涉及的成员变量都被保证是不同的,那么创建一个由这些值索引的新集合,然后对它进行ksort就会更简单、更快:

 foreach($obj_list as $obj)
    $map[$obj->some_var] = $obj;
 ksort($map);
 /// $map now contains the sorted list

If there are duplicate values, you can still avoid usort by utilizing a less known feature of sort that arrays of arrays are sorted by the value of the first scalar member.

如果有重复的值,您仍然可以通过使用一种不太为人知的排序特性来避免usort,即数组的数组按照第一个标量成员的值进行排序。

 foreach($obj_list as $obj)
    $map[] = array($obj->some_var, $obj);
 sort($map); // sorts $map by the value of ->some_var

I guess this still will be 10000000 times faster than usort

我想这仍然比usort快1000万倍。

#15


0  

Here is an option that takes following things into account:

这里有一个考虑以下因素的选项:

  • namespaces
  • 名称空间
  • private properties
  • 私有财产
  • using getter and setter methods
  • 使用getter和setter方法
  • property for sort as parameter
  • 属性作为参数进行排序

PHP

PHP

namespace Dummy;

class Person {

    private $age;

    function __construct($age) {
        $this->setAge($age);
    }

    public function getAge()
    {
        return $this->age;
    }

    public function setAge($age)
    {
        $this->age = $age;
    }
}

class CustomSort{

    public $field = '';

    public function cmp($a, $b)
    {
        return strcmp($a->{'get'.ucfirst($this->field)}(), $b->{'get'.ucfirst($this->field)}());
    }

    public function sortObjectArrayByField($array, $field)
    {
        $this->field = $field;
        usort($array, array("Dummy\CustomSort", "cmp"));
        return $array;
    }
}

$robert = new Person(20);
$peter = new Person(12);
$robin = new Person(44);
$people = array($robert, $peter, $robin);

var_dump( $people );

$customSort = new CustomSort();
$people = $customSort->sortObjectArrayByField($people, 'age');

var_dump( $people );

#1


87  

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.

问题是由于调用比较回调的开销而导致使用usort的效率低下。这个答案考察了使用内置排序函数和非递归快速排序实现之间的区别。

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!

随着PHP自2009年以来的发展,答案随着时间的推移而改变,所以我一直更新它。旧材料,虽然不再相关,仍然是有趣的!

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.1,非递归快速排序并不比使用usort进行回调要快。情况并非总是如此,这就是为什么下面的细节值得一读。真正重要的是,如果你衡量你的问题并尝试其他的方法,你会得到令人惊讶的结果。

Jan 2016 update

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!

现在我们发布了php 7.0和7.1。最后,对于这个数据集,内置的usort总是非常快!

+-----------+------------+------------+------------+------------+------------+
| 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 |
+-----------+------------+------------+------------+------------+------------+

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.

当我在2009年回答这个问题时,我比较了使用usort和非递归快速排序,看看是否有区别。结果显示,快速排序的运行速度比原来快了3倍。

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

因为现在是2015年,所以我认为有必要重新讨论这个问题,所以我使用usort和quicksort对15000个对象进行排序,并在3v4l.org上运行,在很多不同的PHP版本上运行。完整的结果如下: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 |
+-----------+------------+------------+------------+------------+------------+

Original Notes from 2009

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

我尝试了usort,在1.8秒内对15000件物品进行了排序。

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.

当您担心对比较函数的调用效率低下时,我将它与非递归快速排序实现进行了比较。这段时间大约是1 / 3,大约是0。5秒。

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";

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

一个有趣的建议是向类中添加__toString方法并使用sort(),所以我也尝试过了。麻烦的是,必须将SORT_STRING作为第二个参数进行排序,以使其实际调用魔术方法,这具有执行字符串而不是数字排序的副作用。为了解决这个问题,您需要用0填充数字以使其正确排序。最终的结果是,这比usort和自定义快速排序都要慢

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

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

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

$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"

#2


41  

For that specific scenario, you can sort it using the usort() function, where you define your own function to compare the items in the array.

对于特定的场景,可以使用usort()函数对其进行排序,其中定义自己的函数来比较数组中的项。

<?php

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

function personSort( $a, $b ) {
    return $a->age == $b->age ? 0 : ( $a->age > $b->age ) ? 1 : -1;
}

$person1 = new Person(14);
$person2 = new Person(5);
$person3 = new Person(32);
$person4 = new Person(150);
$person5 = new Person(39);
$people = array($person1, $person2, $person3, $person4, $person5);

print_r( $people );

usort( $people, 'personSort' );

print_r( $people );

#3


10  

You could either use usort or a heap.

您可以使用usort或heap。

 class SortPeopleByAge extends SplMaxHeap
  {
      function compare($person1, $person2)
      {
          return $person1->age - $person2->age;
      }
  }

  $people = array(new Person(30), new Person(22), new Person(40));  
  $sorter = new SortPeopleByAge;
  array_map(array($sorter, 'insert'), $people);
  print_r(iterator_to_array($sorter)); // people sorted from 40 to 22

Note that the purpose of an Heap is to have an ordered collection at all times and not to replace usort. For large collections (1000+), a heap will be faster and less memory intensive though.

注意,堆的目的是始终拥有有序的集合,而不是替换usort。对于大型集合(1000+),堆速度更快,内存占用更少。

An added benefit of having Heaps is being able to use their comparison function for callbacks to other sorting functions, like usort. You just have to remember that the order for the comparison is reversed, so any comparison done with a Heap will result in reversed order in usort.

拥有堆的另一个好处是可以将它们的比较函数用于对其他排序函数(如usort)的回调。您只需要记住,比较的顺序是颠倒的,因此任何与堆的比较都将导致usort中的反向顺序。

// using $people array and $sorter
usort($people, array($sorter, 'compare'));
print_r($people); // people sorted from 22 to 40

usort is fine for small to medium collections where you will do the sorting once at the end. Of course, you dont have to have a heap to use usort. You can just as well add any other valid callback for the sorting.

usort对于中、小型的收藏都很合适,最后进行一次排序。当然,使用usort不需要有堆。您也可以为排序添加任何其他有效的回调。

#4


7  

I just coded this. It should be faster than usort as it does not rely on numerous function calls.

我只是编码。它应该比usort更快,因为它不依赖于大量的函数调用。

function sortByProp($array, $propName, $reverse = false)
{
    $sorted = [];

    foreach ($array as $item)
    {
        $sorted[$item->$propName][] = $item;
    }

    if ($reverse) krsort($sorted); else ksort($sorted);
    $result = [];

    foreach ($sorted as $subArray) foreach ($subArray as $item)
    {
        $result[] = $item;
    }

    return $result;
}

Usage:

用法:

$sorted = sortByProp($people, 'age');

Oh, and it uses ksort but it works even if many $people are of the same $age.

哦,它使用ksort,但它能工作,即使很多人都是相同的年龄。

#5


5  

You just need to write a custom comparison function, then use something like usort to do the actual sorting. For example, if the member variable was myVar, you could sort it as follows:

您只需编写一个自定义比较函数,然后使用usort这样的代码进行实际排序。例如,如果成员变量是myVar,您可以将其排序如下:

function cmp($a, $b)
{
    if ($a->myVar == $b->myVar) {
        return 0;
    }
    return ($a->myVar < $b->myVar) ? -1 : 1;
}

usort($myArray, "cmp");

#6


2  

I do not advice my solution in your example because it would be ugly (And I have not benchmarked it), but it works.... And depending of the need, it may help. :)

我不建议我的解决方案在你的例子,因为它丑(和我没有标准的),但它的工作原理....根据需要,它可能会有所帮助。:)

class Person
{
  public $age;

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

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

$person1 = new Person(14);
$person2 = new Person(5);

$persons = array($person1, $person2);
asort($persons);

#7


2  

Here’s a stable Radix Sort implementation for values 0...256:

下面是一个稳定的基数排序实现,其值为0…256:

function radixsort(&$a)
{
    $n = count($a);
    $partition = array();
    for ($slot = 0; $slot < 256; ++$slot) {
        $partition[] = array();
    }
    for ($i = 0; $i < $n; ++$i) {
        $partition[$a[$i]->age & 0xFF][] = &$a[$i];
    } 
    $i = 0;
    for ($slot = 0; $slot < 256; ++$slot) {
        for ($j = 0, $n = count($partition[$slot]); $j < $n; ++$j) {
            $a[$i++] = &$partition[$slot][$j];
        }
    }
}

This costs only O(n) since Radix Sort is a non-comparing sorting algorithm.

这只需花费O(n),因为基数排序是一种非比较排序算法。

#8


2  

One observation is that if the source of the data is from a database, it's probably faster to sort using SQL than it would be within PHP. Of course this is moot if the data source is from a CSV or XML file.

一种观察是,如果数据源来自数据库,那么使用SQL进行排序的速度可能比在PHP中要快。当然,如果数据源来自CSV或XML文件,这是没有意义的。

#9


2  

I went with the following approach: created a function that takes an array of objects, then inside the function I create an associative array using the property as key for the array, then sort they array keys using ksort:

我采用以下方法:创建一个接受对象数组的函数,然后在函数中使用属性作为数组的键,创建一个关联数组,然后使用ksort对它们的数组键进行排序:

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

function sortPerson($persons = Array()){
    foreach($persons as $person){
        $sorted[$person->age] = $person;
    }
    ksort($sorted);
    return array_values($sorted);
}

$person1 = new Person(14);
$person2 = new Person(5);

$persons = array($person1, $person2);
$person = sortPerson($persons);

echo $person[0]->age."\n".$person[1]->age;
/* Output:
5
14
*/

#10


2  

You can do it with ouzo goodies:

你可以用茴香香料来做:

$result = Arrays::sort(array($person1, $person2), Comparator::compareBy('age'));

http://ouzo.readthedocs.org/en/latest/utils/comparators.html

http://ouzo.readthedocs.org/en/latest/utils/comparators.html

#11


1  

usort() or uasort() /* to maintain index association if you were using an associative array */

如果使用关联数组*/,则使用usort()或uasort() /* *来维护索引关联

#12


1  

Yes. If you implement spl ArrayObject in your person object, all the normal php array functions will work properly with it.

是的。如果您在person对象中实现了spl ArrayObject,那么所有正常的php数组函数都可以正常工作。

#13


1  

Try usort: http://www.php.net/manual/en/function.usort.php

试的作用:http://www.php.net/manual/en/function.usort.php

Example:

例子:

<?php
function cmp($obja, $objb)
{
    $a = $obja->sortField;
    $b = $objb->sortField;
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

$a = array( /* your objects */ );

usort($a, "cmp");

?>

#14


1  

If all member variables in question are guaranteed to be different, it will be simpler and faster to create a new collection indexed by these values and then ksort it:

如果所有涉及的成员变量都被保证是不同的,那么创建一个由这些值索引的新集合,然后对它进行ksort就会更简单、更快:

 foreach($obj_list as $obj)
    $map[$obj->some_var] = $obj;
 ksort($map);
 /// $map now contains the sorted list

If there are duplicate values, you can still avoid usort by utilizing a less known feature of sort that arrays of arrays are sorted by the value of the first scalar member.

如果有重复的值,您仍然可以通过使用一种不太为人知的排序特性来避免usort,即数组的数组按照第一个标量成员的值进行排序。

 foreach($obj_list as $obj)
    $map[] = array($obj->some_var, $obj);
 sort($map); // sorts $map by the value of ->some_var

I guess this still will be 10000000 times faster than usort

我想这仍然比usort快1000万倍。

#15


0  

Here is an option that takes following things into account:

这里有一个考虑以下因素的选项:

  • namespaces
  • 名称空间
  • private properties
  • 私有财产
  • using getter and setter methods
  • 使用getter和setter方法
  • property for sort as parameter
  • 属性作为参数进行排序

PHP

PHP

namespace Dummy;

class Person {

    private $age;

    function __construct($age) {
        $this->setAge($age);
    }

    public function getAge()
    {
        return $this->age;
    }

    public function setAge($age)
    {
        $this->age = $age;
    }
}

class CustomSort{

    public $field = '';

    public function cmp($a, $b)
    {
        return strcmp($a->{'get'.ucfirst($this->field)}(), $b->{'get'.ucfirst($this->field)}());
    }

    public function sortObjectArrayByField($array, $field)
    {
        $this->field = $field;
        usort($array, array("Dummy\CustomSort", "cmp"));
        return $array;
    }
}

$robert = new Person(20);
$peter = new Person(12);
$robin = new Person(44);
$people = array($robert, $peter, $robin);

var_dump( $people );

$customSort = new CustomSort();
$people = $customSort->sortObjectArrayByField($people, 'age');

var_dump( $people );