Floydian Posted November 16, 2008 Posted November 16, 2008 Sometimes situations arise where we have an array that contains data for multiple users. For each user, there might be an array of data. One such situation that can arise with this pattern is crime stats. There are certainly many more situations that can arise, but I'm going to use a simplified set of crime stats to demonstrate an easy way to sort a multidimensional array of crime stats. First off, our multidimensional array stores stats for each user as a seperate entry in the main array. The key is the userid. This gives us easy access to each user's data. Suppose the array is called: $stats We might access a user's stats like this: $stats[$userid] Now, $stats[$userid] in my example will be an array of stats for this user. It will contain the number of successes and failures they have had at the crime level they are at. Suppose we wanted to devise a way to generate a table that lists users in order of crime level, then by successes. We might also want to have one that sorts the list by crime level and then failures. Sorting the array isn't so easy because the main array uses the userid as the key and an array as the value. What do you sort in order to sort by crime level then successes? You can't sort the key, because that just puts the list in order of the userid's. And sorting by the array is meaningless because comparing one array to the other doesn't tell us if one person has more or less successes in their crime level. This means we need to sort the entire multidimensional array by looking at the individual user's data one at a time and comparing to the others until the entire thing is sorted. Ouch! That's going to require a recursive function. A recursive function? That means that we loop through the data and perform some comparisons. But looping over it just once won't sort it enough so that we can be sure it's completely sorted. We need to keep going through it until we are sure the sort is finished. That's not the easiest thing in the world to do manually. Luckily for us, php gives us a set of array functions that does that for us. We only need to define the sorting algorithm and then that algorithm is applied recursively to the array. Some folks might be thinking, "algorithm????". I could rephrase that and just say, we need a series of "if blocks" that defines how to sort the array. We're going to use the "uasort()" function. This function takes an array, and sorts it according to a user defined method. It takes two parameters. The first one is the array to sort, and the second one is the name of the function to use to sort the array. That's called a "callback". Our callback function is called by uasort() in order to sort the array. It's called many times. It's called however many times are needed in order to sort the array. And that is determined by how large the array is. Hence the reason we need a recursive function, which uasort() is a recursive function. There are a number of sort functions. usort(), there is no "a" in that function name, does exactly what uasort() does, except that the userid's we have used for the key in the main array would be destroyed by the sorting method. In other words, the sorted array would get new keys starting from 0 and going up in sequential order. It produces a true numerically indexed array. But we want an associative array where the key is not numerically indexed. Hence why we use uasort(). The a in uasort() means "associated", as in, associative array, as opposed to a numerically indexed array. To put it simply, uasort() maintains the original keys and does not overwrite them. And now, here's some sample code that you can fun in your browser after you upload the code to your server. It will run out of the box. I am not sure about php 4 compat, but it definitely works with php 5. <?php /* * This script takes a multidimensional array of crime statistics and sorts them. * The structure of the array is as follows: * 1) The main array is an array of userid's * 2) The inner array is an array of stats for each user * 3) The inner array consists of successes, fails, and the crime level * those stats were obtained at. If the person is at crime level 2, * all the stats are for crime level 2. If the person is at crime level 1, * the stats are for crime level one. So, we're assuming that * every time a player moves up to a new crime level, * a new set of crime stats is started for them * * Then we want to sort the main array according to two seperate parameters. * The first sort we want is to sort according to the crime level, with the * lowest crime level first, going to the highest. * Then we want to sort by successes or fails. */ $stats = array( 3465 => array('success' => 234, 'fail' => 542, 'crime_level' => 2), 5224 => array('success' => 621, 'fail' => 824, 'crime_level' => 1), 7236 => array('success' => 723, 'fail' => 801, 'crime_level' => 1), 1035 => array('success' => 172, 'fail' => 152, 'crime_level' => 2), 8256 => array('success' => 263, 'fail' => 103, 'crime_level' => 2), 5770 => array('success' => 95, 'fail' => 34, 'crime_level' => 1) ); // This function sorts the stats array according to crime level, then successes. function sort_by_successes($a, $b) { /* This function compares two parts of the main array at a time. ($a an $b represent those two parts) $a and $b will contain an array, i.e., success => XXX, fail => XXX, crime_level => XXX So, we have access to the inner array for each of the two parts of the main array we are comparing. This function returns -1, 0, or 1. -1 means $a is less than $b, 0 means $a is equal to $b, and 1 means $a is greater than $b */ // Compare crime level first, since that's the first sort parameter. if ($a['crime_level'] < $b['crime_level']) { // $a is a lower crime level than $b return -1; } elseif ($a['crime_level'] > $b['crime_level']) { // $a is a higher crime level than $b return 1; } else { // If we go to the "else" block, then the crime level is equal and we need to compare the success. // In the next function, we'll compare "fail" here instead. (That's the only difference in the two functions) if ($a['success'] < $b['success']) { // $a has less success then $b return -1; } elseif ($a['success'] > $b['success']) { // $a has more success then $b return 1; } else { // $a has the same success as $b return 0; } } } // This function sorts the stats array according to crime level, then failures. // Please see the comments for the sort_by_successes() function. // It works the same as this function, except that here we look at fail instead of success. function sort_by_failures($a, $b) { if ($a['crime_level'] < $b['crime_level']) { return -1; } elseif ($a['crime_level'] > $b['crime_level']) { return 1; } else { if ($a['fail'] < $b['fail']) { return -1; } elseif ($a['fail'] > $b['fail']) { return 1; } else { return 0; } } } // This function displays the sorted array. function display_results($stats_array) { echo '<pre>' . print_r($stats_array, 1) . '</pre>'; } // Display the array before any sorting has been done. echo "<h3>The unsorted crime stats array.</h3>"; display_results($stats); // Use the uasort() function to sort the stats array and maintain the index (That's the userid, so // we don't want that overwritten... uasort() uses a custom sorting function that // we've defined in order to sort by a custom sorting method. uasort($stats, 'sort_by_successes'); // Now display the results echo "<h3>Crime stats sorted by crime level then successes.</h3>"; display_results($stats); // Now, sort the array again, using a different custom sorting method and display the results. uasort($stats, 'sort_by_failures'); echo "<h3>Crime stats sorted by crime level then failures.</h3>"; display_results($stats); Enjoy! Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.