If I have an object as such:
class Person {
var $age;
function __construct($age) {
$this->age = $age;
}
}
and I have any array
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:
function cmp($a, $b)
{
if ($a->myVar == $b->myVar) {
return 0;
}
return ($a->myVar < $b->myVar) ? -1 : 1;
}
usort($myArray, "cmp");
Here is an option that takes following things into account:
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 );
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
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:
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.
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
You could either use usort or a 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.
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
.
// 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.
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:
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
*/