Sort a PHP associative array by a column

When retrieving information from a database or other data source, you can usually get it delivered to you sorted properly, either through your SQL statement or whatever other method you're using. However, I've found on occasion that the data set I'm working with is messy, usually because I'm pulling from multiple sources or doing some additional manipulation, and I need to present it in order. This takes a little bit of PHP finagling.

For example, let's say you want to show your users the nearest retail location where they can buy product X. You have a data source that provides the retailer name and address of all locations that carry this product. You can determine the user's position either through IP location or browser location detection, so you now have your user's coordinates. By using Google Mapping services you can retrieve the retail locations coordinates, then using some high school trigonometry you can then determine the distance from your user to each location. We'll show our hypothetical resulting array of data:

$locations[0] = Array(
'retailer' => 'Wal-Mart',
'address' => '8320 Lockwood Ridge Road  Sarasota, FL',
'distance' => '35');

$locations[1] = Array(
'retailer' => 'Target',
'address' => '101 North Cattlemen Road, Sarasota, FL',
'distance' => '5');
$locations[2] = Array(
'retailer' => 'K-Mart',
'address' => '7350 Manatee Avenue West, Bradenton, FL',
'distance' => '15');

Now we obviously don't want to return this data to our user in that order, we need to sort it by distance so the Target location is first, then K-Mart and Walmart. I've created a little function to do just this (shown below):

function array_sort_bycolumn(&$array,$column,$dir = 'asc') {
    foreach($array as $a) $sortcol[$a[$column]][] = $a;
    ksort($sortcol);
    foreach($sortcol as $col) {
        foreach($col as $row) $newarr[] = $row;
    }
    
    if($dir=='desc') $array = array_reverse($newarr);
    else $array = $newarr;
}

In our scenario we would call it like this:

array_sort_bycolumn($locations,'distance');

We are passing the array by reference, and saying we want to sort by the distance column in ascending order (the default).

foreach($array as $a) $sortcol[$a[$column]][] = $a;

We iterate through each row of the original array and create a new associative array using the value of the sort column. This creates, in our example, a new array which looks like this:

$sortcol['35'][0] = Array(
'retailer' => 'Wal-Mart',
'address' => '8320 Lockwood Ridge Road  Sarasota, FL',
'distance' => '35');

$sortcol['5'][0] = Array(
'retailer' => 'Target',
'address' => '101 North Cattlemen Road, Sarasota, FL',
'distance' => '5');
$sortcol['15'][0] = Array(
'retailer' => 'K-Mart',
'address' => '7350 Manatee Avenue West, Bradenton, FL',
'distance' => '15');

We add the extra array index in case there are duplicate distances. We wouldn't want to overwrite one of our results.

ksort($sortcol);

We then use the built-in PHP function ksort() to sort the $sortcol array by its keys, which are the distances. Our $sortcol array would now look like this:

$sortcol['5'][0] = Array(
'retailer' => 'Target',
'address' => '101 North Cattlemen Road, Sarasota, FL',
'distance' => '5');

$sortcol['15'][0] = Array(
'retailer' => 'K-Mart',
'address' => '7350 Manatee Avenue West, Bradenton, FL',
'distance' => '15');

$sortcol['35'][0] = Array(
'retailer' => 'Wal-Mart',
'address' => '8320 Lockwood Ridge Road  Sarasota, FL',
'distance' => '35');

We then iterate through the top-level array, then each sub-array to extract the newly sorted array:

foreach($sortcol as $col) { //top-level
    foreach($col as $row) $newarr[] = $row; //sub-level
}

Our new array now looks like this:

$newarr[0] = Array(
'retailer' => 'Target',
'address' => '101 North Cattlemen Road, Sarasota, FL',
'distance' => '5');
$newarr[1] = Array(
'retailer' => 'K-Mart',
'address' => '7350 Manatee Avenue West, Bradenton, FL',
'distance' => '15');

$newarr[2] = Array(
'retailer' => 'Wal-Mart',
'address' => '8320 Lockwood Ridge Road  Sarasota, FL',
'distance' => '35');

We then assign the result to our source array and we are good to go!

if($dir=='desc') $array = array_reverse($newarr);
else $array = $newarr;

Please let me know if you find this helpful!


Contact Sarasota Web Design