Sorting an associative array by a specific key with PHP
One of PHP’s most powerful data types is the array. It can hold numbers, it can hold letters, it can be sorted, sliced and chunked. Speaking of sorting, when sorting an array the straight forward sorting functions are only for sorting by the keys or by the values. What about when you have an array of arrays and want to sort be a specific key in the array? That’s where usort() comes in. First, let’s get our array set up:
$array = array( array('name' => 'Bob', 'weight' => 200), array('name' => 'Rachel', 'weight' => 145), array('name' => 'Arthur', 'weight' => 160), array('name' => 'Paige', 'weight' => 120), array('name' => 'Chris', 'weight' => 135), );
The array above is comprised of arrays that hold the name of a person and their weight. It’s mixed up on purpose so we can sort it.
To use usort() we either need to create a function or use an anonymous function that’s passed it at run time. I’m opting to use separate functions for the examples but will elaborate on how to make an awesome function that’s reusable for any field. To start, let’s create 2 functions, 1 to sort by name and one to sort by weight:
function sortByName($a, $b) $a = $a['name']; $b = $b['name']; if ($a == $b) return 0; return ($a $b) ? -1 : 1; > function sortByWeight($a, $b) $a = $a['weight']; $b = $b['weight']; if ($a == $b) return 0; return ($a $b) ? -1 : 1; >
Why would we need two functions? Well because usort() only passes in 2 arguments to the function, there’s no way to define a single function that can filter by different rows outside of a using a global variable that the functions would have access to. That would get messy pretty quick in my opinion.
So now that we have our functions define, we can use usort() to sort the array by either of the fields like this:
usort($array, 'sortByName'); usort($array, 'sortByWeight');
The array is passed in as a reference so the array itself has it’s elements sorted, no new array is created.
Now that we know how usort() works, let’s address the obvious shortcoming. You could end up creating a whole lot of sort functions to sort by all the different fields you may want to sort by, and even get into more functions to support sorting in descending order instead of ascending. With the power of anonymous functions with create_function() (available since PHP 4.0.1) we can create a single function that we can pass our array to and sort by a specific field. To take it a step further, we can even use an optional argument to determine the direction of the sort:
function sortBy($field, &$array, $direction = 'asc') usort($array, create_function('$a, $b', ' $a = $a["' . $field . '"]; $b = $b["' . $field . '"]; if ($a == $b) return 0; $direction = strtolower(trim($direction)); return ($a ' . ($direction == 'desc' ? '>' : ') .' $b) ? -1 : 1; ')); return true; >
What create_function() allows us to do is generate our sort function on the fly. Because it’s anonymous, it won’t conflict with any other named functions in your code, so that’s not a worry either. The option $direction argument takes the value of “asc” or “desc” and sorts accordingly. Now we have a single function that can be used to sort both by name and by weight with our original array and the array is passed by reference so it retains the same interfacing as usort() already provides. You can now sort like this:
sortBy('name', $array); sortBy('weight', $array);
And if you wanted to sort in the opposite order:
sortBy('name', $array, 'desc'); sortBy('weight', $array, 'desc');
The only real shortcoming of this is that the code doesn’t sanity check if the field exists. This usually isn’t an issue as most data being pulled out of a database would have all the columns even if they didn’t have a value.
This function was adapted from the logic of the Sort class in the PHP framework PICKLES. PICKLES is a PHP framework written by myself (Josh Sherman, the author of this blog) and has been in development for 8 or so years now. The focus of the framework is to give the developer more liberties by doing less while providing a solid foundation to build websites and being highly extendable.
Pardon the shameless self promotion 😉
Good stuff? Want more?
100% Fresh, Grade A Content, Never Spam.
About Josh
Husband. Father. Pug dad. Musician. Founder of Holiday API, Head of Engineering and Emoji Specialist at Mailshake, and author of the best damn Lorem Ipsum Library for PHP.
ksort
Note:
If two members compare as equal, they retain their original order. Prior to PHP 8.0.0, their relative order in the sorted array was undefined.
Note:
Resets array’s internal pointer to the first element.
Parameters
The optional second parameter flags may be used to modify the sorting behavior using these values:
- SORT_REGULAR — compare items normally; the details are described in the comparison operators section
- SORT_NUMERIC — compare items numerically
- SORT_STRING — compare items as strings
- SORT_LOCALE_STRING — compare items as strings, based on the current locale. It uses the locale, which can be changed using setlocale()
- SORT_NATURAL — compare items as strings using «natural ordering» like natsort()
- SORT_FLAG_CASE — can be combined (bitwise OR) with SORT_STRING or SORT_NATURAL to sort strings case-insensitively
Return Values
Always returns true .
Changelog
Version | Description |
---|---|
8.2.0 | The return type is true now; previously, it was bool . |
Examples
Example #1 ksort() example
$fruits = array( «d» => «lemon» , «a» => «orange» , «b» => «banana» , «c» => «apple» );
ksort ( $fruits );
foreach ( $fruits as $key => $val ) echo » $key = $val \n» ;
>
?>?php
The above example will output:
a = orange b = banana c = apple d = lemon
Example #2 ksort() with int keys
$a = [ 0 => ‘First’ , 2 => ‘Last’ , 1 => ‘Middle’ ];
var_dump ( $a );
ksort ( $a );
var_dump ( $a );
?>?php
The above example will output:
array(3) < [0]=>string(5) "First" [2]=> string(4) "Last" [1]=> string(6) "Middle" > array(3) < [0]=>string(5) "First" [1]=> string(6) "Middle" [2]=> string(4) "Last" >
See Also
- sort() — Sort an array in ascending order
- krsort() — Sort an array by key in descending order
- The comparison of array sorting functions
User Contributed Notes 16 notes
A nice way to do sorting of a key on a multi-dimensional array without having to know what keys you have in the array first:
$people = array(
array( «name» => «Bob» , «age» => 8 , «colour» => «red» ),
array( «name» => «Greg» , «age» => 12 , «colour» => «blue» ),
array( «name» => «Andy» , «age» => 5 , «colour» => «purple» ));
foreach( $people as $person ) <
foreach( $person as $key => $value ) <
if(!isset( $sortArray [ $key ])) <
$sortArray [ $key ] = array();
>
$sortArray [ $key ][] = $value ;
>
>
$orderby = «name» ; //change this to whatever key you want from the array
array_multisort ( $sortArray [ $orderby ], SORT_DESC , $people );
var_dump ( $people );
?>
Output from first var_dump:
There’s no checking on whether your array keys exist, or the array data you are searching on is actually there, but easy enough to add.
The first thing that I didn’t find in description it’s that this function return results from MIN value to MAX value, ex: [-5=>», 0=>», 5=>» ]
Also you should know that by default, it has correct sorting for keys that represented as string but has a number as value, ex: [‘-5’=>», ‘0’=>», ‘5’=>» ]
Few examples with results:
DESCRIPTION: Keys are numbers + default flag (SORT_REGULAR)
$arr = [
-5 => ‘minus five’,
0 => ‘zero’,
1 => ‘one’,
2 => ‘two’,
100 => ‘hundred’,
];
Array
(
[-5] => minus five
[0] => zero
[1] => one
[2] => two
[100] => hundred
)
——————————————
DESCRIPTION: Keys are string numbers + default flag (SORT_REGULAR)
Array
(
[-5] => minus five
[0] => zero
[1] => one
[2] => two
[100] => hundred
)
——————————————
DESCRIPTION: Keys are string numbers + SORT_STRING flag
Array
(
[-5] => minus five
[0] => zero
[1] => one
[100] => hundred
[2] => two
)
DESCRIPTION: Keys are string numbers + SORT_NUMERIC flag
Array
(
[-5] => minus five
[0] => zero
[1] => one
[2] => two
[100] => hundred
)
here 2 functions to ksort/uksort an array and all its member arrays
I wrote this function to sort the keys of an array using an array of keynames, in order.
/**
* function array_reorder_keys
* reorder the keys of an array in order of specified keynames; all other nodes not in $keynames will come after last $keyname, in normal array order
* @param array &$array — the array to reorder
* @param mixed $keynames — a csv or array of keynames, in the order that keys should be reordered
*/
function array_reorder_keys (& $array , $keynames ) if(empty( $array ) || ! is_array ( $array ) || empty( $keynames )) return;
if(! is_array ( $keynames )) $keynames = explode ( ‘,’ , $keynames );
if(!empty( $keynames )) $keynames = array_reverse ( $keynames );
foreach( $keynames as $n ) if( array_key_exists ( $n , $array )) $newarray = array( $n => $array [ $n ]); //copy the node before unsetting
unset( $array [ $n ]); //remove the node
$array = $newarray + array_filter ( $array ); //combine copy with filtered array
>
>
>
$seed_array = array( ‘foo’ => ‘bar’ , ‘someotherkey’ => ‘whatev’ , ‘bar’ => ‘baz’ , ‘baz’ => ‘foo’ , ‘anotherkey’ => ‘anotherval’ );
array_reorder_keys ( $seed_array , ‘baz,foo,bar’ ); //returns array(‘baz’=>’foo’, ‘foo’=>’bar’, ‘bar’=>’baz’, ‘someotherkey’=>’whatev’, ‘anotherkey’=>’anotherval’ );
?>
The function that justin at booleangate dot org provides works well, but be aware that it is not a drop-in replacement for ksort as is. While ksort sorts the array by reference and returns a status boolean, natksort returns the sorted array, leaving the original untouched. Thus, you must use this syntax:
If you want to use the more natural syntax:
Then use this modified version:
foreach ($keys as $k) $new_array[$k] = $array[$k];
>
$array = $new_array;
return true;
>
Sorting Arrays
PHP has several functions that deal with sorting arrays, and this document exists to help sort it all out.
- Some sort based on the array keys, whereas others by the values: $array[‘key’] = ‘value’;
- Whether or not the correlation between the keys and values are maintained after the sort, which may mean the keys are reset numerically (0,1,2 . )
- The order of the sort: alphabetical, ascending (low to high), descending (high to low), natural, random, or user defined
- Note: All of these sort functions act directly on the array variable itself, as opposed to returning a new sorted array
- If any of these sort functions evaluates two members as equal then they retain their original order. Prior to PHP 8.0.0, their order were undefined (the sorting was not stable).
Function name | Sorts by | Maintains key association | Order of sort | Related functions |
---|---|---|---|---|
array_multisort() | value | string keys yes, int keys no | first array or sort options | array_walk() |
asort() | value | yes | ascending | arsort() |
arsort() | value | yes | descending | asort() |
krsort() | key | yes | descending | ksort() |
ksort() | key | yes | ascending | krsort() |
natcasesort() | value | yes | natural, case insensitive | natsort() |
natsort() | value | yes | natural | natcasesort() |
rsort() | value | no | descending | sort() |
shuffle() | value | no | random | array_rand() |
sort() | value | no | ascending | rsort() |
uasort() | value | yes | user defined | uksort() |
uksort() | key | yes | user defined | uasort() |
usort() | value | no | user defined | uasort() |
User Contributed Notes 2 notes
While this may seem obvious, user-defined array sorting functions ( uksort(), uasort(), usort() ) will *not* be called if the array does not have *at least two values in it*.
function usortTest ( $a , $b ) var_dump ( $a );
var_dump ( $b );
return — 1 ;
>
$test = array( ‘val1’ );
usort ( $test , «usortTest» );
$test2 = array( ‘val2’ , ‘val3’ );
usort ( $test2 , «usortTest» );
The first array doesn’t get sent to the function.
Please, under no circumstance, place any logic that modifies values, or applies non-sorting business logic in these functions as they will not always be executed.
Another way to do a case case-insensitive sort by key would simply be:
uksort ( $array , ‘strcasecmp’ );
?>
Since strcasecmp is already predefined in php it saves you the trouble to actually write the comparison function yourself.