7

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

2
  • Why does it fail ?What result are you seeing ? Commented Sep 20, 2010 at 7:09
  • In the first attempt, $sort was obviously not found. In the second attempt, I don't know how to refer to the function 'srt'. Commented Sep 20, 2010 at 7:19

5 Answers 5

10

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().)

2
  • Works perfectly. Thanks! If there's a version of the same result that requires less code I'd love to see that too :P Commented Sep 20, 2010 at 7:40
  • Sorry turns out PHP 5.3 wont be available - I need another solution Commented Sep 23, 2010 at 20:34
7

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;
    });
1
  • 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) Commented Sep 20, 2010 at 7:04
0

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

0
0

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');
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.