usortSORT an ARRAY using an
user-defined comparison function.
This function returns TRUE on success or FALSE on failure.
This function will sort an array by its values using a user-supplied comparison function.
If the array you wish to sort needs to be sorted by some non-trivial criteria, you should use this function.
If two members compare as equal, their relative order in the sorted ARRAY is undefined.
This function assigns new keys to the elements in $array.
It will remove any existing keys that may have been assigned, rather than just reordering the keys.
The $value_compare_func, comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
Note that before PHP 7.0.0 this integer had to be in the range from -2147483648 to 2147483647.
<?php
bool usort ( arr &$array , callable $value_compare_func )
where,
&$array = The input ARRAY
$value_compare_func = The comparisson function
?>
&$array
The input ARRAY.
$value_compare_func
An user-defined function.
<?php
int callback ( mix $a, mix $b )
where,
$a = First value to operate this function
$b = Second value to operate this function
?>
CAUTION
Returning non-integer values from the comparison function, such as float, will result in an internal cast to integer of the callback's return value.
So values such as 0.99 and 0.1 will both be cast to an integer value of 0, which will compare such values as equal.
EXERCISE
<?php
function recc01 ( $i, $j )
{
return $i%$j;
}
$arr01u = [2, 8, 18, 3, 7, 9];
echo 'The given ARRAY:<br><pre>';
var_dump($arr01u);
echo '</pre>';
echo '<br>';
usort($arr01u, 'recc01');
echo 'The SORTED ARRAY:<br><pre>';
var_dump($arr01u);
echo '</pre>';
?>
RESULT
The given ARRAY:
array(6) {
[0]=>
int(2)
[1]=>
int(8)
[2]=>
int(18)
[3]=>
int(3)
[4]=>
int(7)
[5]=>
int(9
)
The SORTED ARRAY:
array(6) {
[0]=>
int(7)
[1]=>
int(18)
[2]=>
int(9)
[3]=>
int(3)
[4]=>
int(8)
[5]=>
int(2)
)
EXERCISE
<?php
function recc02 ( $i, $j )
{
return $j%$i;
}
$arr02u = [2, 8, 18, 3, 7, 9];
echo 'The given ARRAY:<br><pre>';
var_dump($arr02u);
echo '</pre>';
echo '<br>';
usort($arr02u, 'recc02');
echo 'The SORTED ARRAY:<br><pre>';
var_dump($arr02u);
echo '</pre>';
?>
RESULT
The given ARRAY:
array(6) {
[0]=>
int(2)
[1]=>
int(8)
[2]=>
int(18)
[3]=>
int(3)
[4]=>
int(7)
[5]=>
int(9
)
The SORTED ARRAY:
array(6) {
[0]=>
int(7)
[1]=>
int(3)
[2]=>
int(9)
[3]=>
int(2)
[4]=>
int(18)
[5]=>
int(8)
)
EXERCISE
<?php
function recc03 ( $i, $j )
{
return $j;
}
$arr03u = [
"Countries" => [ 'BRA' => "Brasil",
'POR' => "Portugal", 'JPN' => "Japan" ],
"Continents" => ['SA' => "South America",
'EU' => "Europe", 'AS' => "Asia"]
];
echo 'The given ARRAY:<br><pre>';
var_dump($arr03u);
echo '</pre>';
echo '<br>';
usort($arr03u, 'recc03');
echo 'The SORTED ARRAY:<br><pre>';
var_dump($arr03u);
echo '</pre>';
?>
RESULT
The given ARRAY:
array(2) {
["Countries"]=>
array(3) {
["BRA"]=>
string(6) "Brasil"
["POR"]=>
string(8) "Portugal"
["JPN"]=>
string(5) "Japan"
}
["Continents"]=>
array(3) {
["SA"]=>
string(13) "South America"
["EU"]=>
string(6) "Europe"
["AS"]=>
string(4) "Asia"
}
}
The SORTED ARRAY:
array(2) {
[0]=>
array(3) {
["SA"]=>
string(13) "South America"
["EU"]=>
string(6) "Europe"
["AS"]=>
string(4) "Asia"
}
[1]=>
array(3) {
["BRA"]=>
string(6) "Brasil"
["POR"]=>
string(8) "Portugal"
["JPN"]=>
string(5) "Japan"
}
}
EXERCISE
<?php
function recc04 ( $i, $j )
{
echo $j . '<br><br>' . $i;
}
$arr04u = [
"english" => 'unconstitutional',
"portuguese" => 'inconstitucional'];
echo 'The given ARRAY:<br><pre>';
var_dump($arr04u);
echo '</pre><br>The SORTED ARRAY:<br><br>';
usort($arr04u, 'recc04');
?>
RESULT
The given ARRAY:
array(2) {
["english"]=>
string(16) "unconstitutional"
["portuguese"]=>
string(16) "inconstitucional"
}
The SORTED ARRAY:
inconstitucional
unconstitutional
EXERCISE
<?php
function recc05($i, $j)
{
return strcmp($i[0], $j[0]);
}
$colors[0][0] = "RED";
$colors[1][0] = "GREEN";
$colors[2][0] = "BLUE";
usort($colors, "recc05");
echo '<pre>';
var_dump($colors);
echo '</pre>';
$c = count($colors) - 1;
for($x = 0; $x <= $c; $x++)
{
echo $x . ' => ' . $colors[$x][0] . '<br>';
}
?>
RESULT
array(3) {
[0]=>
array(1) {
[0]=>
string(4) "BLUE"
}
[1]=>
array(1) {
[0]=>
string(5) "GREEN"
}
[2]=>
array(1) {
[0]=>
string(3) "RED"
}
}
or
0 => BLUE
1 => GREEN
2 => RED
EXERCISE
<?php
/*
* Test basic functionality of usort()
* with indexed and associative arrays
*/
echo "Testing usort() : basic functionality.";
function cmp($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else
return -1;
}
// Int array with default keys
$int_values = array(1, 8, 9, 3, 2, 6, 7);
echo "<br><br>Numeric array with default keys:<br>";
var_dump( usort($int_values, 'cmp') );
echo '<br><br>';
var_dump($int_values);
// String array with default keys
$string_values = array("This", "is", 'a', "test");
echo "<br><br>String array with default keys:<br>";
var_dump( usort($string_values, 'cmp') );
echo '<br><br>';
var_dump($string_values);
// Associative array with numeric keys
$numeric_key_arg = array(1=> 1, 2 => 2, 3 => 7, 5 => 4, 4 => 9);
echo "<br><br>Associative array with numeric keys:<br>";
var_dump( usort($numeric_key_arg, 'cmp') );
echo '<br><br>';
var_dump($numeric_key_arg);
// Associative array with string keys
$string_key_arg = array('one' => 4, 'two' => 2, 'three' => 1, 'four' => 10);
echo "<br><br>Associative array with string keys:<br>";
var_dump( usort($string_key_arg, 'cmp') );
echo '<br><br>';
var_dump($string_key_arg);
?>
EXERCISE
<?php
$array = range(0, 10000);
usort($array, function($a, $b) {
// Everything is equal!
return 0;
});
var_dump($array === range(0, 10000));
?>
RESULT
Run this exercise on different versions of PHP to see the differences in the results.
EXERCISE
<?php
/*
* Pass an array with duplicate keys
* and values to usort() to test behaviour
*/
echo "Testing usort() : usage variation.";
function cmp($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else
return -1;
}
// Array with duplicate string
// and integer keys and values
$array_arg = [ 0 => 2, "a" => 8, "d" => 9,
3 => 3, 5 => 2, "o" => 6,
"z" => -99, 0 => 1, "z" => 3 ];
echo "<br><br>Array with duplicate keys:<br>";
var_dump( usort($array_arg, 'cmp') );
echo '<br><br>';
var_dump($array_arg);
// Array with default and assigned keys
$array_arg = [ 0 => "Banana", 1 => "Mango",
"Orange", 2 => "Apple", "Pineapple" ];
echo "<br><br>Array with default/assigned keys:<br>";
var_dump( usort($array_arg, 'cmp') );
echo '<br><br>';
var_dump($array_arg);
?>
EXERCISE
<?php
/*
* Pass an array with different
* data types as keys to usort()
* to test how it is re-ordered
*/
echo "Testing usort() : usage variation.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return -1;
}
else {
return 1;
}
}
// different heredoc strings
// single line heredoc string
$simple_heredoc = <<<EOT2
simple
EOT2;
// multiline heredoc string
$multiline_heredoc = <<<EOT3
multiline heredoc with 123
and speci@! ch@r..\ncheck\talso
EOT3;
$array_arg = array(
// numeric keys
-2 => 9,
8.9 => 8,
012 => 7,
0x34 => 6,
// string keys
'key' => 5, //single quoted key
"two" => 4, //double quoted key
" " => 0, // space as key
// bool keys
TRUE => 100,
FALSE => 25,
// null keys
NULL => 35,
// binary key
"a".chr(0)."b" => 45,
b"binary" => 30,
//heredoc keys
$simple_heredoc => 75,
$multiline_heredoc => 200,
// default key
1,
);
var_dump( usort($array_arg, 'cmp_function') );
echo "<br><br>Sorted array after usort() function call:<br><pre>";
var_dump($array_arg);
echo '</pre>';
?>
EXERCISE
<?php
/*
* Pass arrays of numeric data to usort()
* to test how it is re-ordered
*/
echo "Testing usort() : usage variation.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else {
return -1;
}
}
// Int array
$int_values = [ 0 => 3, 1 => 2, 3 => 100,
4 => 150, 5 => 25, 6 => 350,
7 => 0, 8 => -3, 9 => -1200 ];
echo "<br><br>Sorting Integer array:<br>";
var_dump( usort($int_values, 'cmp_function') );
echo "<br><br>";
var_dump($int_values);
// Octal array
$octal_values = [ 0 => 056, 1 => 023, 2 => 00,
3 => 015, 4 => -045, 5 => 01,
6 => -07 ];
echo "<br><br>Sorting Octal array:<br>";
var_dump( usort($octal_values, 'cmp_function') );
echo "<br><br>";
var_dump($octal_values);
// Hexadecimal array
$hex_values = [ 0 => 0xAE, 1 => 0x2B,
2 => 0X10, 3 => -0xCF,
4 => 0X12, 5 => -0XF2 ];
echo "<br><br>Sorting Hex array:<br>";
var_dump( usort($hex_values, 'cmp_function') );
echo "<br><br>";
var_dump($hex_values);
// Float array
$float_values = [ 0 => 10.2,
1 => 2.4,
2 => -3.4,
3 => 0, 4 => 0.5,
5 => 7.3e3,
6 => -9.34E-2 ];
echo "<br><br>Sorting Float array:<br>";
var_dump( usort($float_values, 'cmp_function') );
echo "<br><br>";
var_dump($float_values);
// empty array
$empty_array = array();
echo "<br><br>Sorting empty array:<br>";
var_dump( usort($empty_array, 'cmp_function') );
echo "<br><br>";
var_dump($empty_array);
?>
EXERCISE
<?php
/*
* Pass arrays of string data to usort()
* to test how it is re-ordered
*/
echo "Testing usort() : usage variation.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else {
return -1;
}
}
// Different heredoc strings to be sorted
$empty_heredoc =<<<EOT
EOT;
$simple_heredoc1 =<<<EOT
Heredoc
EOT;
$simple_heredoc2 =<<<EOT
HEREDOC
EOT;
$multiline_heredoc =<<<EOT
heredoc string\twith!@# and 123
Test this!!!
EOT;
// Single quoted strings
$single_quoted_values = array(
0 => ' ', 1 => 'test', 3 => 'Hello', 4 => 'HELLO',
5 => '', 6 => '\t', 7 => '0', 8 => '123Hello',
9 => '\'', 10 => '@#$%'
);
echo "<br><br>Sorting Single Quoted String values:<br>";
var_dump( usort($single_quoted_values, 'cmp_function') );
echo "<br><br>";
var_dump($single_quoted_values);
// Double quoted strings
$double_quoted_values = array(
0 => " ", 1 => "test", 3 => "Hello", 4 => "HELLO",
5 => "", 6 => "\t", 7 => "0", 8 => "123Hello",
9 => "\"", 10 => "@#$%"
);
echo "<br><br>Sorting Double Quoted String values:<br>";
var_dump( usort($double_quoted_values, 'cmp_function') );
echo "<br><br>";
var_dump($double_quoted_values);
// Heredoc strings
$heredoc_values = array(0 => $empty_heredoc, 1 => $simple_heredoc1,
2 => $simple_heredoc2, 3 => $multiline_heredoc);
echo "<br><br>Sorting Heredoc String values:<br>";
var_dump( usort($heredoc_values, 'cmp_function') );
echo "<br><br>";
var_dump($heredoc_values);
?>
EXERCISE
<?php
/*
* Pass a multi-dimensional array as
* $array_arg argument to usort()
* to test how array is re-ordered
*/
echo "Testing usort() : usage variation.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else {
return -1;
}
}
$array_args = array(
0 => array(2, 10, -1),
1 => array(100),
2 => array(),
3 => array(0),
4 => array(-1),
5 => array(-9, 34, 54, 0, 20),
6 => array(''),
7 => array("apple", "Apple", "APPLE", "aPPle", "aPpLe")
);
$temp_array = $array_args;
echo "<br><br>Pass usort() a two-dimensional array:<br>";
// sorting array_arg as whole array
var_dump( usort($temp_array, 'cmp_function') );
echo "<br><br>Array after call to usort():<br>";
var_dump($temp_array);
echo "<br><br>Pass usort() a sub-array:<br>";
var_dump( usort($array_args[5], 'cmp_function') );
echo "<br><br>Array after call to usort():<br>";
var_dump($array_args[5]);
?>
EXERCISE
<?php
/*
* Pass an anonymous comparison
* function as $cmp_function argument
* to test behaviour()
*/
echo "Testing usort() : usage variation.";
$cmp_function = function($value1, $value2) {
if ($value1 == $value2) { return 0; }
else if ($value1 > $value2) { return 1; }
else { return -1; }
};
$array_arg = array(0 => 100,
1 => 3,
2 => -70,
3 => 24,
4 => 90);
echo "<br><br>Anonymous 'cmp_function'
with parameters passed by value:<br>";
var_dump( usort($array_arg, $cmp_function) );
echo "<br><br>";
var_dump($array_arg);
$array_arg = array("b" => "Banana",
"m" => "Mango",
"a" => "Apple",
"p" => "Pineapple");
$cmp_function = function(&$value1, &$value2) {
if ($value1 == $value2) { return 0; }
else if ($value1 > $value2) { return 1; }
else { return -1; }
};
echo "<br><br>Anonymous 'cmp_function'
with parameters passed by reference:<br>";
var_dump( usort($array_arg, $cmp_function) );
echo "<br><br>";
var_dump($array_arg);
?>
EXERCISE
<?php
/*
* Test usort() when comparison function is:
* 1. a built in comparison function
* 2. a language construct
*/
echo "Testing usort() : usage variation.";
// Initializing variables
$array_arg = [ "b" => "Banana",
"m" => "Mango",
"a" => "apple",
"p" => "Pineapple",
"o" => "orange"];
// Testing library functions as comparison function
echo "<br><br>Testing usort()
with built-in
'cmp_function': strcasecmp():<br>";
$temp_array1 = $array_arg;
var_dump( usort($temp_array1, 'strcasecmp') );
echo "<br><br>";
var_dump($temp_array1);
echo "<br><br>Testing usort()
with built-in
'cmp_function': strcmp():<br>";
$temp_array2 = $array_arg;
var_dump( usort($temp_array2, 'strcmp') );
echo "<br><br>";
var_dump($temp_array2);
?>
EXERCISE
<?php
/*
* Pass an array of referenced
* variables as $array_arg to
* test behaviour
*/
echo "Testing usort() : usage variation.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else {
return -1;
}
}
// different variables which are used
// as elements of $array_arg
$value1 = -5;
$value2 = 100;
$value3 = 0;
$value4 = &$value1;
// array_args an array containing
// elements with reference variables
$array_arg = [
0 => 10,
1 => &$value4,
2 => &$value2,
3 => 200,
4 => &$value3,
];
echo "<br><br>Sorting \$array_arg
containing different
references:<br>";
var_dump( usort($array_arg, 'cmp_function') );
echo "<br><br>";
var_dump($array_arg);
?>
EXERCISE
<?php
set_error_handler(function($code, $message) {
var_dump($code, $message);
});
$comparator= null;
$list= [1, 4, 2, 3, -1];
usort($list, function($a, $b) use ($comparator) {
try {
return $comparator->compare($a, $b);
} catch (Error $e) {
var_dump($e->getCode(), $e->getMessage());
echo "<br><br>";
return 0;
}
});
var_dump($list);
?>
EXERCISE
<?php
/*
* Pass an array of objects which
* have a different number of properties
* to test behaviour of usort()
*/
echo "Testing usort() : object functionality.<br>";
function simple_cmp($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else
return -1;
}
// comparison function for SimpleClass2
// objects which has more than one member
function multiple_cmp($value1, $value2)
{
if($value1->getValue() == $value2->getValue())
return 0;
else if($value1->getValue() > $value2->getValue())
return 1;
else
return -1;
}
// Simple class with single property
class SimpleClass1
{
private $int_value;
public function __construct($value) {
$this->int_value = $value;
}
}
// Simple class with more than one property
class SimpleClass2
{
private $int_value;
protected $float_value;
public $string_value;
public function __construct($int, $float, $str) {
$this->int_value = $int;
$this->float_value = $float;
$this->string_value = $str;
}
public function getValue() {
return $this->int_value;
}
}
// array of SimpleClass objects with only one property
$array_arg = array(
0 => new SimpleClass1(10),
1 => new SimpleClass1(1),
2 => new SimpleClass1(100),
3 => new SimpleClass1(50)
);
echo '<br>';
var_dump( usort($array_arg, 'simple_cmp') );
echo '<br><pre>';
var_dump($array_arg);
echo '</pre>';
// array of SimpleClass objects having more than one properties
$array_arg = array(
0 => new SimpleClass2(2, 3.4, "mango"),
1 => new SimpleClass2(10, 1.2, "apple"),
2 => new SimpleClass2(5, 2.5, "orange"),
);
echo '<br>';
var_dump( usort($array_arg, 'multiple_cmp') );
echo '<br><pre>';
var_dump($array_arg);
echo '</pre>';
?>
EXERCISE
<?php
/*
* Pass an array of objects which are either:
* 1. Empty
* 2. Static
* 2. Inherited
* to test behaviour of usort()
*/
echo "Testing usort() : object functionality.";
function cmp_function($value1, $value2)
{
if($value1 == $value2) {
return 0;
}
else if($value1 > $value2) {
return 1;
}
else
return -1;
}
// Class without any member
class EmptyClass
{
}
// Class with static member
class StaticClass
{
public static $static_value;
public function __construct($value) {
StaticClass::$static_value = $value;
}
}
// Abstract class
abstract class AbstractClass
{
public $pub_value;
public abstract function abstractMethod();
}
// Child class extending abstract class
class ChildClass extends AbstractClass
{
public $child_value = 100;
public function abstractMethod() {
$pub_value = 5;
}
public function __construct($value) {
$this->child_value = $value;
}
}
// Testing uasort with StaticClass
// objects as elements of 'array_arg'
echo "<br><br>Testing usort() with StaticClass objects:<br>";
$array_arg = array(
0 => new StaticClass(20),
1 => new StaticClass(50),
2 => new StaticClass(15),
3 => new StaticClass(70),
);
echo '<br>';
var_dump( usort($array_arg, 'cmp_function') );
echo '<br><pre>';
var_dump($array_arg);
echo '</pre>';
// Testing uasort with EmptyClass objects
// as elements of 'array_arg'
echo "<br><br>Testing usort() with EmptyClass objects:<br>";
$array_arg = array(
0 => new EmptyClass(),
1 => new EmptyClass(),
2 => new EmptyClass(),
3 => new EmptyClass(),
);
echo '<br>';
var_dump( usort($array_arg, 'cmp_function') );
echo '<br><pre>';
var_dump($array_arg);
echo '</pre>';
// Testing uasort with ChildClass objects
// as elements of 'array_arg'
echo "<br><br>Testing usort() with ChildClass objects:<br>";
$array_arg = array(
0 => new ChildClass(20),
1 => new ChildClass(500),
2 => new ChildClass(15),
3 => new ChildClass(700),
);
echo '<br>';
var_dump( usort($array_arg, 'cmp_function') );
echo '<br><pre>';
var_dump($array_arg);
echo '</pre>';
?>