home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


Programming PHPProgramming PHPSearch this book

5.8. Sorting

Sorting changes the internal order of elements in an array and optionally rewrites the keys to reflect this new order. For example, you might use sorting to arrange a list of scores from biggest to smallest, to alphabetize a list of names, or to order a set of users based on how many messages they posted.

PHP provides three ways to sort arrays—sorting by keys, sorting by values without changing the keys, or sorting by values and then changing the keys. Each kind of sort can be done in ascending order, descending order, or an order defined by a user-defined function.

5.8.1. Sorting One Array at a Time

The functions provided by PHP to sort an array are shown in Table 5-1.

Table 5-1. PHP functions for sorting an array

Effect

Ascending

Descending

User-defined order

Sort array by values, then reassign indexes starting with 0

sort( )

rsort( )

usort( )

Sort array by values

asort( )

arsort( )

uasort( )

Sort array by keys

ksort( )

krsort( )

uksort( )

The sort( ), rsort( ), and usort( ) functions are designed to work on indexed arrays, because they assign new numeric keys to represent the ordering. They're useful when you need to answer questions like "what are the top 10 scores?" and "who's the third person in alphabetical order?" The other sort functions can be used on indexed arrays, but you'll only be able to access the sorted ordering by using traversal functions such as foreach and next.

To sort names into ascending alphabetical order, you'd use this:

$names = array('cath', 'angela', 'brad', 'dave');
sort($names);                // $names is now 'angela', 'brad', 'cath', 'dave'

To get them in reverse alphabetic order, simply call rsort( ) instead of sort( ).

If you have an associative array mapping usernames to minutes of login time, you can use arsort( ) to display a table of the top three, as shown here:

$logins = array('njt' => 415,
                'kt'  => 492,
                'rl'  => 652,
                'jht' => 441,
                'jj'  => 441,
                'wt'  => 402);
arsort($logins);
$num_printed = 0;
echo("<table>\n");
foreach ($logins as $user => $time ) {
  echo("<tr><td>$user</td><td>$time</td></tr>\n");
  if (++$num_printed == 3) {
    break;                   // stop after three
  }
}
echo("</table>\n");
<table>
<tr><td>rl</td><td>652</td></tr>
<tr><td>kt</td><td>492</td></tr>
<tr><td>jht</td><td>441</td></tr>
</table>

If you want that table displayed in ascending order by username, use ksort( ):

ksort($logins);
echo("<table>\n");
foreach ($logins as $user => $time) {
  echo("<tr><td>$user</td><td>$time</td></tr>\n");
}
echo("</table>\n");
<table>
<tr><td>jht</td><td>441</td></tr>
<tr><td>jj</td><td>441</td></tr>
<tr><td>kt</td><td>492</td></tr>
<tr><td>njt</td><td>415</td></tr>
<tr><td>rl</td><td>652</td></tr>
<tr><td>wt</td><td>402</td></tr>
</table>

User-defined ordering requires that you provide a function that takes two values and returns a value that specifies the order of the two values in the sorted array. The function should return 1 if the first value is greater than the second, -1 if the first value is less than the second, and 0 if the values are the same for the purposes of your custom sort order.

Example 5-3 is a program that lets you try the various sorting functions on the same data.

Example 5-3. Sorting arrays

<?php
 function user_sort($a, $b) {
   // smarts is all-important, so sort it first
   if($b == 'smarts') {
     return 1;
   }
   else if($a == 'smarts') {
     return -1;
   }

   return ($a == $b) ? 0 : (($a < $b) ? -1 : 1);
 }

 $values = array('name' => 'Buzz Lightyear',
                 'email_address' => 'buzz@starcommand.gal',
                 'age' => 32,
                 'smarts' => 'some');

 if($submitted) {
   if($sort_type == 'usort' || $sort_type == 'uksort' || $sort_type == 'uasort') {
     $sort_type($values, 'user_sort');
   }
   else {
     $sort_type($values);
   }
 }
?>

<form action="index.php">
 <p>
   <input type="radio" name="sort_type" value="sort" checked="checked" />
                                                           Standard sort<br />
   <input type="radio" name="sort_type" value="rsort" />   Reverse sort<br />
   <input type="radio" name="sort_type" value="usort" />   User-defined sort<br />
   <input type="radio" name="sort_type" value="ksort" />   Key sort<br />
   <input type="radio" name="sort_type" value="krsort" />  Reverse key sort<br />
   <input type="radio" name="sort_type" value="uksort" />  User-defined key sort<br />
   <input type="radio" name="sort_type" value="asort" />  Value sort<br />
   <input type="radio" name="sort_type" value="arsort" /> Reverse value sort<br />
   <input type="radio" name="sort_type" value="uasort" /> User-defined value sort<br />
 </p>

 <p align="center">
    <input type="submit" value="Sort" name="submitted" />
 </p>

 <p>
    Values <?= $submitted ? "sorted by $sort_type" : "unsorted"; ?>:
 </p>

 <ul>
   <?php
    foreach($values as $key=>$value) {
      echo "<li><b>$key</b>: $value</li>";
    }
   ?>
 </ul>
</form>

5.8.3. Sorting Multiple Arrays at Once

The array_multisort( ) function sorts multiple indexed arrays at once:

array_multisort(array1 [, array2, ... ]);

Pass it a series of arrays and sorting orders (identified by the SORT_ASC or SORT_DESC constants), and it reorders the elements of all the arrays, assigning new indexes. It is similar to a join operation on a relational database.

Imagine that you have a lot of people, and several pieces of data on each person:

$names = array('Tom', 'Dick',  'Harriet', 'Brenda', 'Joe');
$ages  = array(25,    35,      29,        35,       35);
$zips  = array(80522, '02140', 90210,     64141,    80522);

The first element of each array represents a single record—all the information known about Tom. Similarly, the second element constitutes another record—all the information known about Dick. The array_multisort( ) function reorders the elements of the arrays, preserving the records. That is, if Dick ends up first in the $names array after the sort, the rest of Dick's information will be first in the other arrays too. (Note that we needed to quote Dick's zip code to prevent it from being interpreted as an octal constant.)

Here's how to sort the records first ascending by age, then descending by zip code:

array_multisort($ages, SORT_ASC, $zips, SORT_DESC, $names, SORT_ASC);

We need to include $names in the function call to ensure that Dick's name stays with his age and zip code. Printing out the data shows the result of the sort:

echo("<table>\n");
for ($i=0; $i < count($names); $i++) {
  echo("<tr><td>$ages[$i]</td><td>$zips[$i]</td><td>$names[$i]</td>\n");
}
echo("</table>\n");
<table>
<tr><td>25</td><td>80522</td><td>Tom</td>
<tr><td>29</td><td>90210</td><td>Harriet</td>
<tr><td>35</td><td>80522</td><td>Joe</td>
<tr><td>35</td><td>64141</td><td>Brenda</td>
<tr><td>35</td><td>02140</td><td>Dick</td>
</table>


Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.