FUDforum
Fast Uncompromising Discussions. FUDforum will get your users talking.

Home » Imported messages » comp.lang.php » sort array of objects by muliple values
Show: Today's Messages :: Polls :: Message Navigator
Switch to threaded view of this topic Create a new topic Submit Reply
sort array of objects by muliple values [message #172015] Thu, 27 January 2011 19:04 Go to next message
Max is currently offline  Max
Messages: 4
Registered: January 2011
Karma: 0
Junior Member
Is there a simple way to sort $array below like SQL it does? I.e.
ORDER BY birthday ASC, name ASC
Output would be Kevin, Michael, Alice

Thanks!

<?php
class User {
private $firstname;
private $surname;
private $birthday;

function __construct($firstname, $surname, $birthday) {
$this->firstname = $name;
$this->surname = $surname;
$this->birthday = $birthday;
}
function __get($n) {
return $this->$n;
}
}


$array = array (
new User('Alice', 'Smith', '1960-01-01'),
new User('Michael', 'Jordan', '1950-01-01'),
new User('Kevin', 'Dilan', '1950-01-01'),
);
Re: sort array of objects by muliple values [message #172016 is a reply to message #172015] Thu, 27 January 2011 19:10 Go to previous messageGo to next message
Jerry Stuckle is currently offline  Jerry Stuckle
Messages: 2598
Registered: September 2010
Karma: 0
Senior Member
On 1/27/2011 2:04 PM, Max wrote:
> Is there a simple way to sort $array below like SQL it does? I.e.
> ORDER BY birthday ASC, name ASC
> Output would be Kevin, Michael, Alice
>
> Thanks!
>
> <?php
> class User {
> private $firstname;
> private $surname;
> private $birthday;
>
> function __construct($firstname, $surname, $birthday) {
> $this->firstname = $name;
> $this->surname = $surname;
> $this->birthday = $birthday;
> }
> function __get($n) {
> return $this->$n;
> }
> }
>
>
> $array = array (
> new User('Alice', 'Smith', '1960-01-01'),
> new User('Michael', 'Jordan', '1950-01-01'),
> new User('Kevin', 'Dilan', '1950-01-01'),
> );

Use usort() with a static member function. See

http://us2.php.net/manual/en/function.usort.php

for an example.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex(at)attglobal(dot)net
==================
Re: sort array of objects by muliple values [message #172019 is a reply to message #172016] Thu, 27 January 2011 19:59 Go to previous messageGo to next message
Max is currently offline  Max
Messages: 4
Registered: January 2011
Karma: 0
Junior Member
On Jan 27, 8:10 pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
> On 1/27/2011 2:04 PM, Max wrote:
>
>
>
>
>
>
>
>
>
>> Is there a simple way to sort $array below like SQL it does? I.e.
>> ORDER BY birthday ASC, name ASC
>> Output would be Kevin, Michael, Alice
>
>> Thanks!
>
>> <?php
>> class User {
>>      private $firstname;
>>      private $surname;
>>      private $birthday;
>
>>      function __construct($firstname, $surname, $birthday) {
>>          $this->firstname = $name;
>>          $this->surname = $surname;
>>          $this->birthday = $birthday;
>>      }
>>      function __get($n) {
>>          return $this->$n;
>>      }
>> }
>
>> $array = array (
>>          new User('Alice',       'Smith',  '1960-01-01'),
>>          new User('Michael',   'Jordan',  '1950-01-01'),
>>          new User('Kevin',      'Dilan',    '1950-01-01'),
>>          );
>
> Use usort() with a static member function.  See
>
> http://us2.php.net/manual/en/function.usort.php
>
> for an example.

it sorts only by one field

>
> --
> ==================
> Remove the "x" from my email address
> Jerry Stuckle
> JDS Computer Training Corp.
> jstuck...@attglobal.net
> ==================
Re: sort array of objects by muliple values [message #172021 is a reply to message #172019] Thu, 27 January 2011 20:44 Go to previous messageGo to next message
Jerry Stuckle is currently offline  Jerry Stuckle
Messages: 2598
Registered: September 2010
Karma: 0
Senior Member
On 1/27/2011 2:59 PM, Max wrote:
> On Jan 27, 8:10 pm, Jerry Stuckle<jstuck...@attglobal.net> wrote:
>> On 1/27/2011 2:04 PM, Max wrote:
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>> Is there a simple way to sort $array below like SQL it does? I.e.
>>> ORDER BY birthday ASC, name ASC
>>> Output would be Kevin, Michael, Alice
>>
>>> Thanks!
>>
>>> <?php
>>> class User {
>>> private $firstname;
>>> private $surname;
>>> private $birthday;
>>
>>> function __construct($firstname, $surname, $birthday) {
>>> $this->firstname = $name;
>>> $this->surname = $surname;
>>> $this->birthday = $birthday;
>>> }
>>> function __get($n) {
>>> return $this->$n;
>>> }
>>> }
>>
>>> $array = array (
>>> new User('Alice', 'Smith', '1960-01-01'),
>>> new User('Michael', 'Jordan', '1950-01-01'),
>>> new User('Kevin', 'Dilan', '1950-01-01'),
>>> );
>>
>> Use usort() with a static member function. See
>>
>> http://us2.php.net/manual/en/function.usort.php
>>
>> for an example.
>
> it sorts only by one field
>

So, change the function to compare by birthday then name.

--
==================
Remove the "x" from my email address
Jerry Stuckle
JDS Computer Training Corp.
jstucklex(at)attglobal(dot)net
==================
Re: sort array of objects by muliple values [message #172024 is a reply to message #172019] Thu, 27 January 2011 20:46 Go to previous messageGo to next message
Peter H. Coffin is currently offline  Peter H. Coffin
Messages: 245
Registered: September 2010
Karma: 0
Senior Member
On Thu, 27 Jan 2011 11:59:28 -0800 (PST), Max wrote:
> On Jan 27, 8:10?pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>> On 1/27/2011 2:04 PM, Max wrote:
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>> Is there a simple way to sort $array below like SQL it does? I.e.
>>> ORDER BY birthday ASC, name ASC
>>> Output would be Kevin, Michael, Alice
>>
>>> Thanks!
>>
>>> <?php
>>> class User {
>>> ? ? ?private $firstname;
>>> ? ? ?private $surname;
>>> ? ? ?private $birthday;
>>
>>> ? ? ?function __construct($firstname, $surname, $birthday) {
>>> ? ? ? ? ?$this->firstname = $name;
>>> ? ? ? ? ?$this->surname = $surname;
>>> ? ? ? ? ?$this->birthday = $birthday;
>>> ? ? ?}
>>> ? ? ?function __get($n) {
>>> ? ? ? ? ?return $this->$n;
>>> ? ? ?}
>>> }
>>
>>> $array = array (
>>> ? ? ? ? ?new User('Alice', ? ? ? 'Smith', ?'1960-01-01'),
>>> ? ? ? ? ?new User('Michael', ? 'Jordan', ?'1950-01-01'),
>>> ? ? ? ? ?new User('Kevin', ? ? ?'Dilan', ? ?'1950-01-01'),
>>> ? ? ? ? ?);
>>
>> Use usort() with a static member function. ?See
>>
>> http://us2.php.net/manual/en/function.usort.php
>>
>> for an example.
>
> it sorts only by one field

If you sort a sorted array by another column, what do you think happens
to the records in identically-keyed records?

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting. [TOFU := text oben,
Q: What is the most annoying thing on usenet? followup unten]
Re: sort array of objects by muliple values [message #172027 is a reply to message #172019] Thu, 27 January 2011 21:27 Go to previous messageGo to next message
Denis McMahon is currently offline  Denis McMahon
Messages: 634
Registered: September 2010
Karma: 0
Senior Member
On 27/01/11 19:59, Max wrote:
> On Jan 27, 8:10 pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>> On 1/27/2011 2:04 PM, Max wrote:
>>
>>> Is there a simple way to sort $array below like SQL it does? I.e.
>>> ORDER BY birthday ASC, name ASC
>>> Output would be Kevin, Michael, Alice
>>
>>> Thanks!
>>
>>> <?php
>>> class User {
>>> private $firstname;
>>> private $surname;
>>> private $birthday;
>>
>>> function __construct($firstname, $surname, $birthday) {
>>> $this->firstname = $name;
>>> $this->surname = $surname;
>>> $this->birthday = $birthday;
>>> }
>>> function __get($n) {
>>> return $this->$n;
>>> }
>>> }
>>
>>> $array = array (
>>> new User('Alice', 'Smith', '1960-01-01'),
>>> new User('Michael', 'Jordan', '1950-01-01'),
>>> new User('Kevin', 'Dilan', '1950-01-01'),
>>> );
>>
>> Use usort() with a static member function. See
>>
>> http://us2.php.net/manual/en/function.usort.php
>>
>> for an example.
>
> it sorts only by one field

The thing with a user defined sort is that you have to write the sort
function yourself, and it can sort on whatever you want it to:

<?php

class User {
private $firstname;
private $surname;
private $birthday;

function __construct($firstname, $surname, $birthday) {
$this->firstname = $firstname;
$this->surname = $surname;
$this->birthday = $birthday;
}
function __get($n) {
return $this->$n;
}
}

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

$a = array (
new User('Alice', 'Smith', '1960-01-01'),
new User('Michael', 'Jordan', '1950-01-01'),
new User('Kevin', 'Dilan', '1950-01-01'),
);

print "Before Sort\n===========\n";

foreach ($a as $key => $value) {
print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
{$value->birthday}\n";
}

usort($a, "cmp_User");

print "\nAfter Sort\n==========\n";

foreach ($a as $key => $value) {
print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
{$value->birthday}\n";
}

?>

generates:

Before Sort
===========
Item 0; Name: Smith, Alice; DOB: 1960-01-01
Item 1; Name: Jordan, Michael; DOB: 1950-01-01
Item 2; Name: Dilan, Kevin; DOB: 1950-01-01

After Sort
==========
Item 0; Name: Dilan, Kevin; DOB: 1950-01-01
Item 1; Name: Jordan, Michael; DOB: 1950-01-01
Item 2; Name: Smith, Alice; DOB: 1960-01-01

Rgds

Denis McMahon
Re: sort array of objects by muliple values [message #172028 is a reply to message #172024] Thu, 27 January 2011 21:31 Go to previous messageGo to next message
Denis McMahon is currently offline  Denis McMahon
Messages: 634
Registered: September 2010
Karma: 0
Senior Member
On 27/01/11 20:46, Peter H. Coffin wrote:
> On Thu, 27 Jan 2011 11:59:28 -0800 (PST), Max wrote:
>> On Jan 27, 8:10?pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>>> On 1/27/2011 2:04 PM, Max wrote:
>>>
>>>> Is there a simple way to sort $array below like SQL it does? I.e.
>>>> ORDER BY birthday ASC, name ASC
>>>> Output would be Kevin, Michael, Alice
>>>
>>>> Thanks!
>>>
>>>> <?php
>>>> class User {
>>>> ? ? ?private $firstname;
>>>> ? ? ?private $surname;
>>>> ? ? ?private $birthday;
>>>
>>>> ? ? ?function __construct($firstname, $surname, $birthday) {
>>>> ? ? ? ? ?$this->firstname = $name;
>>>> ? ? ? ? ?$this->surname = $surname;
>>>> ? ? ? ? ?$this->birthday = $birthday;
>>>> ? ? ?}
>>>> ? ? ?function __get($n) {
>>>> ? ? ? ? ?return $this->$n;
>>>> ? ? ?}
>>>> }
>>>
>>>> $array = array (
>>>> ? ? ? ? ?new User('Alice', ? ? ? 'Smith', ?'1960-01-01'),
>>>> ? ? ? ? ?new User('Michael', ? 'Jordan', ?'1950-01-01'),
>>>> ? ? ? ? ?new User('Kevin', ? ? ?'Dilan', ? ?'1950-01-01'),
>>>> ? ? ? ? ?);
>>>
>>> Use usort() with a static member function. ?See
>>>
>>> http://us2.php.net/manual/en/function.usort.php
>>>
>>> for an example.
>>
>> it sorts only by one field
>
> If you sort a sorted array by another column, what do you think happens
> to the records in identically-keyed records?

It's not an array of columns, it's an array of records (or objects
defined by the class constructor), and what he needs is a compare
function callback for usort that's aware of the class structure and the
properties he wants to sort by.

Pretty trivial exercise really.

Rgds

Denis McMahon
Re: sort array of objects by muliple values [message #172029 is a reply to message #172027] Thu, 27 January 2011 21:38 Go to previous messageGo to next message
Max is currently offline  Max
Messages: 4
Registered: January 2011
Karma: 0
Junior Member
On Jan 27, 10:27 pm, Denis McMahon <denis.m.f.mcma...@googlemail.com>
wrote:
> On 27/01/11 19:59, Max wrote:
>
>
>
>
>
>
>
>
>
>> On Jan 27, 8:10 pm, Jerry Stuckle <jstuck...@attglobal.net> wrote:
>>> On 1/27/2011 2:04 PM, Max wrote:
>
>>>> Is there a simple way to sort $array below like SQL it does? I.e.
>>>> ORDER BY birthday ASC, name ASC
>>>> Output would be Kevin, Michael, Alice
>
>>>> Thanks!
>
>>>> <?php
>>>> class User {
>>>>      private $firstname;
>>>>      private $surname;
>>>>      private $birthday;
>
>>>>      function __construct($firstname, $surname, $birthday) {
>>>>          $this->firstname = $name;
>>>>          $this->surname = $surname;
>>>>          $this->birthday = $birthday;
>>>>      }
>>>>      function __get($n) {
>>>>          return $this->$n;
>>>>      }
>>>> }
>
>>>> $array = array (
>>>>          new User('Alice',       'Smith',  '1960-01-01'),
>>>>          new User('Michael',   'Jordan',  '1950-01-01'),
>>>>          new User('Kevin',      'Dilan',    '1950-01-01'),
>>>>          );
>
>>> Use usort() with a static member function.  See
>
>>> http://us2.php.net/manual/en/function.usort.php
>
>>> for an example.
>
>> it sorts only by one field
>
> The thing with a user defined sort is that you have to write the sort
> function yourself, and it can sort on whatever you want it to:
>
> <?php
>
> class User {
>     private $firstname;
>     private $surname;
>     private $birthday;
>
>     function __construct($firstname, $surname, $birthday) {
>         $this->firstname = $firstname;
>         $this->surname = $surname;
>         $this->birthday = $birthday;
>     }
>     function __get($n) {
>         return $this->$n;
>     }
>
> }
>
> function cmp_User($a, $b)
> {
>     if ($a->birthday == $b->birthday) {
>         if ($a->surname == $b->surname) {
>             return 0;
>         }
>         return ($a->surname < $b->surname) ? -1 : 1;
>     }
>     return ($a->birthday < $b->birthday) ? -1 : 1;
>
> }
>
> $a = array (
>         new User('Alice',   'Smith',  '1960-01-01'),
>         new User('Michael', 'Jordan', '1950-01-01'),
>         new User('Kevin',   'Dilan',  '1950-01-01'),
>         );
>
> print "Before Sort\n===========\n";
>
> foreach ($a as $key => $value) {
>     print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
> {$value->birthday}\n";
>
> }
>
> usort($a, "cmp_User");
>
> print "\nAfter Sort\n==========\n";
>
> foreach ($a as $key => $value) {
>     print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
> {$value->birthday}\n";
>
> }
>
> ?>
>
> generates:
>
> Before Sort
> ===========
> Item 0; Name: Smith, Alice; DOB: 1960-01-01
> Item 1; Name: Jordan, Michael; DOB: 1950-01-01
> Item 2; Name: Dilan, Kevin; DOB: 1950-01-01
>
> After Sort
> ==========
> Item 0; Name: Dilan, Kevin; DOB: 1950-01-01
> Item 1; Name: Jordan, Michael; DOB: 1950-01-01
> Item 2; Name: Smith, Alice; DOB: 1960-01-01
>
> Rgds
>
> Denis McMahon

Thanks for example! What if sort direction and/or fields only known at
runtime?
Re: sort array of objects by muliple values [message #172030 is a reply to message #172029] Thu, 27 January 2011 23:11 Go to previous messageGo to next message
Denis McMahon is currently offline  Denis McMahon
Messages: 634
Registered: September 2010
Karma: 0
Senior Member
On 27/01/11 21:38, Max wrote:
> On Jan 27, 10:27 pm, Denis McMahon <denis.m.f.mcma...@googlemail.com>
> wrote:

>> <?php
>>
>> class User {
>> private $firstname;
>> private $surname;
>> private $birthday;
>>
>> function __construct($firstname, $surname, $birthday) {
>> $this->firstname = $firstname;
>> $this->surname = $surname;
>> $this->birthday = $birthday;
>> }
>> function __get($n) {
>> return $this->$n;
>> }
>>
>> }
>>
>> function cmp_User($a, $b)
>> {
>> if ($a->birthday == $b->birthday) {
>> if ($a->surname == $b->surname) {
>> return 0;
>> }
>> return ($a->surname < $b->surname) ? -1 : 1;
>> }
>> return ($a->birthday < $b->birthday) ? -1 : 1;
>>
>> }
>>
>> $a = array (
>> new User('Alice', 'Smith', '1960-01-01'),
>> new User('Michael', 'Jordan', '1950-01-01'),
>> new User('Kevin', 'Dilan', '1950-01-01'),
>> );
>>
>> print "Before Sort\n===========\n";
>>
>> foreach ($a as $key => $value) {
>> print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
>> {$value->birthday}\n";
>>
>> }
>>
>> usort($a, "cmp_User");
>>
>> print "\nAfter Sort\n==========\n";
>>
>> foreach ($a as $key => $value) {
>> print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
>> {$value->birthday}\n";
>>
>> }
>>
>> ?>
>>
>> generates:
>>
>> Before Sort
>> ===========
>> Item 0; Name: Smith, Alice; DOB: 1960-01-01
>> Item 1; Name: Jordan, Michael; DOB: 1950-01-01
>> Item 2; Name: Dilan, Kevin; DOB: 1950-01-01
>>
>> After Sort
>> ==========
>> Item 0; Name: Dilan, Kevin; DOB: 1950-01-01
>> Item 1; Name: Jordan, Michael; DOB: 1950-01-01
>> Item 2; Name: Smith, Alice; DOB: 1960-01-01
>>
>> Rgds
>>
>> Denis McMahon
>
> Thanks for example! What if sort direction and/or fields only known at
> runtime?

Then your callback function becomes a bit more complex.

You could define the sort properties order and direction before calling
the sort function, and then use that in the sort:

<?php

class User {
private $firstname;
private $surname;
private $birthday;

function __construct($firstname, $surname, $birthday) {
$this->firstname = $firstname;
$this->surname = $surname;
$this->birthday = $birthday;
}
function __get($n) {
return $this->$n;
}
}

$sortparams = array("birthday" => "desc", "surname" => "asc",
"firstname" => "asc");

function cmp_User($a, $b) {
global $sortparams;
foreach ($sortparams as $member => $dir) {
if ($a->$member == $b->$member) continue;
if ($dir == "asc") {
return ($a->$member < $b->$member) ? -1 : 1;
}
else if ($dir == "desc") {
return ($b->$member < $a->$member) ? -1 : 1;
}
}
return 0;
}

$a = array (
new User('Michael', 'Jordan', '1950-01-01'),
new User('Alice', 'Smith', '1960-01-01'),
new User('Kevin', 'Dilan', '1950-01-01'),
new User('Fred', 'Jordan', '1950-01-01'),
new User('John', 'Doe', '1960-01-01'),
new User('Pete', 'Jones', '1960-01-01'),
);

print "Before Sort\n===========\n";

foreach ($a as $key => $value) {
print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
{$value->birthday}\n";
}

usort($a, "cmp_User");

print "\nAfter Sort\n==========\n";

foreach ($a as $key => $value) {
print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
{$value->birthday}\n";
}

?>

Generates:

Before Sort
===========
Item 0; Name: Jordan, Michael; DOB: 1950-01-01
Item 1; Name: Smith, Alice; DOB: 1960-01-01
Item 2; Name: Dilan, Kevin; DOB: 1950-01-01
Item 3; Name: Jordan, Fred; DOB: 1950-01-01
Item 4; Name: Doe, John; DOB: 1960-01-01
Item 5; Name: Jones, Pete; DOB: 1960-01-01

After Sort
==========
Item 0; Name: Doe, John; DOB: 1960-01-01
Item 1; Name: Jones, Pete; DOB: 1960-01-01
Item 2; Name: Smith, Alice; DOB: 1960-01-01
Item 3; Name: Dilan, Kevin; DOB: 1950-01-01
Item 4; Name: Jordan, Fred; DOB: 1950-01-01
Item 5; Name: Jordan, Michael; DOB: 1950-01-01
Re: sort array of objects by muliple values [message #172031 is a reply to message #172030] Thu, 27 January 2011 23:21 Go to previous messageGo to next message
Denis McMahon is currently offline  Denis McMahon
Messages: 634
Registered: September 2010
Karma: 0
Senior Member
On 27/01/11 23:11, Denis McMahon wrote:

> <?php
>
> class User {
> private $firstname;
> private $surname;
> private $birthday;
>
> function __construct($firstname, $surname, $birthday) {
> $this->firstname = $firstname;
> $this->surname = $surname;
> $this->birthday = $birthday;
> }
> function __get($n) {
> return $this->$n;
> }
> }
>
> $sortparams = array("birthday" => "desc", "surname" => "asc",
> "firstname" => "asc");
>
> function cmp_User($a, $b) {
> global $sortparams;
> foreach ($sortparams as $member => $dir) {
> if ($a->$member == $b->$member) continue;
> if ($dir == "asc") {
> return ($a->$member < $b->$member) ? -1 : 1;
> }
> else if ($dir == "desc") {
> return ($b->$member < $a->$member) ? -1 : 1;
> }
> }
> return 0;
> }
>
> $a = array (
> new User('Michael', 'Jordan', '1950-01-01'),
> new User('Alice', 'Smith', '1960-01-01'),
> new User('Kevin', 'Dilan', '1950-01-01'),
> new User('Fred', 'Jordan', '1950-01-01'),
> new User('John', 'Doe', '1960-01-01'),
> new User('Pete', 'Jones', '1960-01-01'),
> );
>
> print "Before Sort\n===========\n";
>
> foreach ($a as $key => $value) {
> print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
> {$value->birthday}\n";
> }
>
> usort($a, "cmp_User");
>
> print "\nAfter Sort\n==========\n";
>
> foreach ($a as $key => $value) {
> print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
> {$value->birthday}\n";
> }
>
> ?>
>
> Generates:
>
> Before Sort
> ===========
> Item 0; Name: Jordan, Michael; DOB: 1950-01-01
> Item 1; Name: Smith, Alice; DOB: 1960-01-01
> Item 2; Name: Dilan, Kevin; DOB: 1950-01-01
> Item 3; Name: Jordan, Fred; DOB: 1950-01-01
> Item 4; Name: Doe, John; DOB: 1960-01-01
> Item 5; Name: Jones, Pete; DOB: 1960-01-01
>
> After Sort
> ==========
> Item 0; Name: Doe, John; DOB: 1960-01-01
> Item 1; Name: Jones, Pete; DOB: 1960-01-01
> Item 2; Name: Smith, Alice; DOB: 1960-01-01
> Item 3; Name: Dilan, Kevin; DOB: 1950-01-01
> Item 4; Name: Jordan, Fred; DOB: 1950-01-01
> Item 5; Name: Jordan, Michael; DOB: 1950-01-01

Of course, the more logical place to set up $sortparams would be
immediately before the usort that it referred to.

There's probably a better method to pass the array to the callback
involving writing the callback function as a member of the class, but
I'm not really into writing classes.

Rgds

Denis McMahon
Re: sort array of objects by muliple values [message #172044 is a reply to message #172031] Fri, 28 January 2011 08:47 Go to previous messageGo to next message
Max is currently offline  Max
Messages: 4
Registered: January 2011
Karma: 0
Junior Member
On Jan 28, 12:21 am, Denis McMahon <denis.m.f.mcma...@googlemail.com>
wrote:
> On 27/01/11 23:11, Denis McMahon wrote:
>
>
>
>> <?php
>
>> class User {
>>     private $firstname;
>>     private $surname;
>>     private $birthday;
>
>>     function __construct($firstname, $surname, $birthday) {
>>         $this->firstname = $firstname;
>>         $this->surname = $surname;
>>         $this->birthday = $birthday;
>>     }
>>     function __get($n) {
>>         return $this->$n;
>>     }
>> }
>
>> $sortparams = array("birthday" => "desc", "surname" => "asc",
>> "firstname" => "asc");
>
>> function cmp_User($a, $b) {
>>     global $sortparams;
>>     foreach ($sortparams as $member => $dir) {
>>         if ($a->$member == $b->$member) continue;
>>         if ($dir == "asc") {
>>             return ($a->$member < $b->$member) ? -1 : 1;
>>         }
>>         else if ($dir == "desc") {
>>             return ($b->$member < $a->$member) ? -1 : 1;
>>         }
>>     }
>>     return 0;
>> }
>
>> $a = array (
>>         new User('Michael', 'Jordan', '1950-01-01'),
>>         new User('Alice',   'Smith',  '1960-01-01'),
>>         new User('Kevin',   'Dilan',  '1950-01-01'),
>>         new User('Fred',    'Jordan', '1950-01-01'),
>>         new User('John',    'Doe',    '1960-01-01'),
>>         new User('Pete',    'Jones',  '1960-01-01'),
>>         );
>
>> print "Before Sort\n===========\n";
>
>> foreach ($a as $key => $value) {
>>     print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
>> {$value->birthday}\n";
>> }
>
>> usort($a, "cmp_User");
>
>> print "\nAfter Sort\n==========\n";
>
>> foreach ($a as $key => $value) {
>>     print "Item $key; Name: {$value->surname}, {$value->firstname}; DOB:
>> {$value->birthday}\n";
>> }
>
>> ?>
>
>> Generates:
>
>> Before Sort
>> ===========
>> Item 0; Name: Jordan, Michael; DOB: 1950-01-01
>> Item 1; Name: Smith, Alice; DOB: 1960-01-01
>> Item 2; Name: Dilan, Kevin; DOB: 1950-01-01
>> Item 3; Name: Jordan, Fred; DOB: 1950-01-01
>> Item 4; Name: Doe, John; DOB: 1960-01-01
>> Item 5; Name: Jones, Pete; DOB: 1960-01-01
>
>> After Sort
>> ==========
>> Item 0; Name: Doe, John; DOB: 1960-01-01
>> Item 1; Name: Jones, Pete; DOB: 1960-01-01
>> Item 2; Name: Smith, Alice; DOB: 1960-01-01
>> Item 3; Name: Dilan, Kevin; DOB: 1950-01-01
>> Item 4; Name: Jordan, Fred; DOB: 1950-01-01
>> Item 5; Name: Jordan, Michael; DOB: 1950-01-01
>
> Of course, the more logical place to set up $sortparams would be
> immediately before the usort that it referred to.
>
> There's probably a better method to pass the array to the callback
> involving writing the callback function as a member of the class, but
> I'm not really into writing classes.
>
> Rgds
>
> Denis McMahon

Many thanks for great help!
Re: sort array of objects by muliple values [message #172047 is a reply to message #172029] Fri, 28 January 2011 11:06 Go to previous message
Helmut Chang is currently offline  Helmut Chang
Messages: 22
Registered: September 2010
Karma: 0
Junior Member
Am 27.01.2011 22:38, schrieb Max:
> On Jan 27, 10:27 pm, Denis McMahon<denis.m.f.mcma...@googlemail.com>
> wrote:
>>
>> <?php
>>
>> class User {
>> private $firstname;
>> private $surname;
>> private $birthday;
>>
>> function __construct($firstname, $surname, $birthday) {
>> $this->firstname = $firstname;
>> $this->surname = $surname;
>> $this->birthday = $birthday;
>> }
>> function __get($n) {
>> return $this->$n;
>> }
>>
>> }
>>
>> function cmp_User($a, $b)
>> {
>> if ($a->birthday == $b->birthday) {
>> if ($a->surname == $b->surname) {
>> return 0;
>> }
>> return ($a->surname< $b->surname) ? -1 : 1;
>> }
>> return ($a->birthday< $b->birthday) ? -1 : 1;
>>
>> }
>>
>> $a = array (
>> new User('Alice', 'Smith', '1960-01-01'),
>> new User('Michael', 'Jordan', '1950-01-01'),
>> new User('Kevin', 'Dilan', '1950-01-01'),
>> );
>>
>> [...]
>>
>> usort($a, "cmp_User");
>
> Thanks for example! What if sort direction and/or fields only known at
> runtime?

Besides Denis' solution, you could also write a comparer class, which
is, what I do:

abstract class RecordComparer {

const SortAscending = 1;
const SortDescending = -1;

protected $_direction;

public function __construct($direction) {
$this->_direction;
}

// Some basic methods to compare different datatypes
protected function _compareStringProperty($a, $b, $property) {
// I use strcoll here, because it's locale aware
return strcoll($a->{$property}, $b->{$property};
}

protected function _compareNumberProperty($a, $b, $property) {
return $a->{$property} - $b->{$property};
}

...
}

class UserComparer extends RecordComparer {

public function compareByFirstname(User $a, User $b) {
$result = $this->_compareStringProperty($a, $b, 'Firstname')
* $this->_direction;

// Sort by lastname, if firstname is equal:
if ($result === 0)
$result = $this->compareByLastname($a, $b);

return $result;
}

// ...implement a method for each property that should be sortable...
}

$a = array (
new User('Alice', 'Smith', '1960-01-01'),
new User('Michael', 'Jordan', '1950-01-01'),
new User('Kevin', 'Dilan', '1950-01-01'),
);

// The manual doesn't state this, but usort can also take instances of
// a class:
$comparer = new UserComparer(UserComparer::SortAscending);
usort($a, array($comparer, 'compareByLastname');
usort($a, array($ocmparer, 'compareByFirstname');
....

But I admit, this concept may not fit for you, if you want to decide
during runtime a complex sorting on multiple properties with varying
directions, like

Lastname ASC, Birthday DESC
or
Lastname ASC, Birthday ASC

It works, if you want to have something like this:

Sort by lastname, but if they are equal, automatically sort records with
equal lastnames by their birthdays, etc.

HTH, Helmut
  Switch to threaded view of this topic Create a new topic Submit Reply
Previous Topic: SNMPv3 for PHP?
Next Topic: Using server to list CSS page list in menu
Goto Forum:
  

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ]

Current Time: Mon Nov 25 23:53:05 GMT 2024

Total time taken to generate the page: 0.05592 seconds