[ Team LiB ] Previous Section Next Section

21.3 Sorting with a Comparison Function

The built-in sorting functions are appropriate in the overwhelming majority of situations. If your problem requires a sort that performs better than the one used in the built-in functions, you are faced with coding your own. If your problem is that you need to compare complex elements, such as objects or multidimensional arrays, the solution is to write a comparison function and plug it into the usort function.

The usort function allows you to sort an array using your own comparison function. Your comparison function must accept two values and return an integer. The two arguments are compared, and if a negative number is returned, then the values are considered to be in order. If zero is returned, they are considered to be equal. A positive number signifies that the numbers are out of order.

In Listing 21.5, I've created a multidimensional array with three elements for name, title, and hourly rate. Sometimes I want to be able list employees by name, but other times I might want to list them by title or how much they make per hour. To solve this problem, I've written three comparison functions. Output is shown in Figure 21.4.

Listing 21.5 Using the usort function
<?php
    class EmployeeTracker
    {
        static $title = array(
            "President"=>1,
            "Executive"=>2,
            "Manager"=>3,
            "Programmer"=>4
            );

        public $employees;

        public function __construct($data)
        {
            $this->employees = $data;
        }

        // byName
        // compare employees based on name
        function byName($left, $right)
        {
            return(strcmp($left[0], $right[0]));
        }

        // byTitle
        // compare employees based on title
        function byTitle($left, $right)
        {
            if($left[1] == $right[1])
            {
                return(0);
            }
            else
            {
                return(EmployeeTracker::$title[$left[1]] -
                    EmployeeTracker::$title[$right[1]]);
            }
        }
        // bySalary
        // compare employees based on salary, then name
        function bySalary($left, $right)
        {
            if($left[2] == $right[2])
            {
                return(byName($left, $right));
            }
            else
            {
                return($right[2] - $left[2]);
            }
        }

        // printEmployees
        // send entire list of employees to browser
        function printEmployees()
        {
            foreach($this->employees as $value)
            {
                printf("%s (%s) %.2f/Hour <br>\n",
                    $value[0],
                     $value[1],
                    $value[2]);
            }
        }
    }

    // Create some employees (Name, Title, Rate)
    $e = new EmployeeTracker(array(
        array("Mckillop, Jeff", "Executive", 50),
        array("Porter, Carl", "Manager", 45),
        array("Marazzani, Rick", "Manager", 35),
        array("Dibetta, Bob", "Programmer", 65),
        array("Atkinson, Leon", "President", 100)));

    print("<b>Unsorted</b><br>\n");
    $e->printEmployees();

    print("<B>Sorted by Name</B><br>\n");
    usort($e->employees, array($e, "byName"));
    $e->printEmployees();

    print("<b>Sorted by Title</b><br>\n");
    usort($e->employees, array($e, "byTitle"));
    $e->printEmployees();

    print("<b>Sorted by Rate</b><br>\n");
    usort($e->employees, array($e, "bySalary"));
    $e->printEmployees();
?>
Figure 21.4. Output of Listing 21.5.

graphics/21fig04.jpg

The byName function is a simple wrapper for strcmp. Names will be ordered by ASCII code. The byTitle function assigns an integer value to each title and then returns the comparison of these integers. The bySalary function compares the wage element, but if two employees make the same amount of money per hour, their names are compared.

    [ Team LiB ] Previous Section Next Section