views:

121

answers:

5

I have an array full of objects from the same class. I'd like to sort this array by optional object field, for instance $case->ID or $case->Sender

Is there a built in flavor of the array_sort() function that does this already, or will I have to write this sort function myself?

Answer doesn't have to explain in detail - this is more like a yes/no question

Thanks


My failed attempt at usort:

function sortBy($sort)
  {
   usort($this->abuseCases, function($a, $b) {
     if($a->{$sort} > $b->{$sort}) return 1;
     if($a->{$sort} < $b->{$sort}) return -1;
     else return 0;
    });
  }

Another failed attempt:

    function sortBy($sort)
    {
        $this->sortBy = $sort;

        usort($this->abuseCases, array("this", "srt"));
    }

    private function srt($a, $b)
    {
        if($a->{$this->sortBy} > $b->{$this->sortBy}) return 1;
        if($a->{$this->sortBy} < $b->{$this->sortBy}) return -1;
        else return 0;
    }

Edit for bump

+6  A: 

You can use usort as:

function cmp( $a, $b ) {    
  return ($a->ID - $b->ID); // assuming numeric ID
} 

usort($arrayOfObjects,'cmp');

IN PHP >= 5.3 you can also use anonymous function as:

usort($arrayOfObjects, function($a, $b) {
        return $a->ID - $b->ID;
    });
codaddict
Thanks for the reply. Do you know of any methods of getting a pre-defined variable into this sort function? My attempt failed (I've edited it into the main post)
Codemonkey
A: 

You will have to write it, but it's pretty trivial with usort():

function my_obj_sort($a, $b) {
    return strnatcasecmp($a->Sender, $b->Sender);
}

usort($cases, 'my_obj_sort');
Adam Backstrom
A: 

You should take a look at the usort() function. It accepts a callback that does custom sorting, which is what you want.

Vasileios Lourdas
+4  A: 

You can use not only an anonymous function but a closure, like e.g.

function ($a,$b) use ($sort) { ... }

and $sort will be available in the function body. Self-contained example:

<?php
function getFn($sort) {
  return function($a, $b) use($sort) {
    if($a->$sort > $b->$sort) return 1;
    if($a->$sort < $b->$sort) return -1;
    return 0;
  };
}

$abuseCases = array(
  (object)array('ID'=>1, 'Sender'=>'Sender A'),
  (object)array('ID'=>3, 'Sender'=>'Sender D'),
  (object)array('ID'=>2, 'Sender'=>'Sender C'),
  (object)array('ID'=>4, 'Sender'=>'Sender B')
);

echo "\n----- Sort By Sender ----\n";
usort($abuseCases, getFn('Sender'));
foo($abuseCases);

echo "\n----- Sort By ID ----\n";
usort($abuseCases, getFn('ID'));
foo($abuseCases);

function foo($a) {
  foreach($a as $o) {
    echo $o->ID, ' ', $o->Sender, "\n";
  }
}

prints

----- Sort By Sender ----
1 Sender A
4 Sender B
2 Sender C
3 Sender D

----- Sort By ID ----
1 Sender A
2 Sender C
3 Sender D
4 Sender B

Update: With php<5.3 you can use an object instead of an anonymous function. usort() expects the second parameter to be a callable. That can be an anoymous function as of php 5.3, but it can also be the name of a function ....or an object and a method name passed as an array like array($obj, 'methodName').

$abuseCases = getData();
echo "\n----- Sort By Sender ----\n";
usort($abuseCases, array(new Foo('Sender'), 'compare'));
foo($abuseCases);

echo "\n----- Sort By ID ----\n";
usort($abuseCases, array(new Foo('ID'), 'compare'));
foo($abuseCases);

class Foo {
  public $propName; // protected?
  public function __construct($propertyName) {
    $this->propName = $propertyName;
  }
  public function compare($a, $b) {
    $prop = $this->propName;
    if($a->$prop > $b->$prop) return 1;
    if($a->$prop < $b->$prop) return -1;
    return 0;
  }
}

function foo($a) {
  foreach($a as $o) {
    echo $o->ID, ' ', $o->Sender, "\n";
  }
}
function getData() {
  return array(
    (object)array('ID'=>1, 'Sender'=>'Sender A'),
    (object)array('ID'=>3, 'Sender'=>'Sender D'),
    (object)array('ID'=>2, 'Sender'=>'Sender C'),
    (object)array('ID'=>4, 'Sender'=>'Sender B')
  );
}

(If you make heavy use of this - or don't want to write excuses like this one -_- - you might want to define an interface like interface Comparator { ... }, let Foo implement that interface and have some function/class that uses Comparator, i.e. a wrapper for objects around usort().)

VolkerK
A good example of closures usage. Works only with PHP 5.3+
Iacopo
Works perfectly. Thanks! If there's a version of the same result that requires less code I'd love to see that too :P
Codemonkey
Sorry turns out PHP 5.3 wont be available - I need another solution
Codemonkey
see update ....
VolkerK
A: 

From the design POV a better option would be to use a dedicated object (like CasesCollection) instead of plain arrays. You could make sort key a member of this object and trivially refer to it as $this->sortKey in the sorting callback.

stereofrog