(PHP 4, PHP 5, PHP 7, PHP 8)
usort — Trie un tableau en utilisant une fonction de comparaison
Trie array
sur place suivant les valeurs
en utilisant une fonction de comparaison définie par l'utilisateur.
Note:
Si deux membres se comparent comme égaux, ils maintiennent leur ordre original. Antérieur à PHP 8.0.0, leur ordre relatif dans le tableau trié n'est pas défini.
Note: Cette fonction assigne de nouvelles clés aux éléments dans
array
. Elle effacera toutes les clés existantes qui ont pu être assignées, plutôt que de réarranger les clés.
array
Le tableau d'entrée.
callback
La fonction de comparaison doit retourner un entier inférieur à, égal à, ou supérieur à 0 si le premier argument est considéré comme, respectivement, inférieur à, égal à, ou supérieur au second.
Retourner des valeurs non-entières à partir de la fonction
de comparaison, telles que float , entraînera une conversion interne
de la valeur de retour du rappel en int . Ainsi, des valeurs telles que
0.99
et 0.1
seront toutes deux converties en une
valeur entière de 0
, ce qui comparera de telles valeurs comme égales.
Retourne toujours true
.
Version | Description |
---|---|
8.2.0 |
Le type de retour est maintenant true , auparavant il était bool .
|
8.0.0 |
Si callback attend un paramètre à être passé par
référence, cette fonction émet désormais une E_WARNING .
|
Exemple #1 Exemple avec usort()
<?php
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
?>
L'exemple ci-dessus va afficher :
0: 1 1: 2 2: 3 3: 5 4: 6
L'opérateur combiné peut être utilisé pour simplifier la comparaison interne.
<?php
function cmp($a, $b)
{
return $a <=> $b;
}
$a = array(3, 2, 5, 6, 1);
usort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
?>
Note:
Évidemment dans ce cas trivial, sort() serait plus approprié.
Exemple #2 Tri avec usort() sur un tableau multidimensionnel
<?php
function cmp($a, $b)
{
return strcmp($a["fruit"], $b["fruit"]);
}
$fruits[0]["fruit"] = "lemons";
$fruits[1]["fruit"] = "apples";
$fruits[2]["fruit"] = "grapes";
usort($fruits, "cmp");
foreach ($fruits as $key => $value) {
echo "\$fruits[$key]: " . $value["fruit"] . "\n";
}
?>
L'exemple ci-dessus va afficher :
$fruits[0]: apples $fruits[1]: grapes $fruits[2]: lemons
Lors du tri de tableau multidimensionnel, $a et $b contiennent des références sur le premier élément du tableau.
Exemple #3 Tri avec usort() sur un objet
<?php
class TestObj {
public string $name;
function __construct($name)
{
$this->name = $name;
}
/* Ceci est une fonction de comparaison statique */
static function cmp_obj($a, $b)
{
return strtolower($a->name) <=> strtolower($b->name);
}
}
$a[] = new TestObj("c");
$a[] = new TestObj("b");
$a[] = new TestObj("d");
usort($a, [TestObj::class, "cmp_obj"]);
foreach ($a as $item) {
echo $item->name . "\n";
}
?>
L'exemple ci-dessus va afficher :
b c d
Exemple #4 Exemple avec usort() en utilisant une closure pour trier un tableau multidimensionnel
<?php
$array[0] = array('key_a' => 'z', 'key_b' => 'c');
$array[1] = array('key_a' => 'x', 'key_b' => 'b');
$array[2] = array('key_a' => 'y', 'key_b' => 'a');
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('key_b'));
foreach ($array as $item) {
echo $item['key_a'] . ', ' . $item['key_b'] . "\n";
}
?>
L'exemple ci-dessus va afficher :
y, a x, b z, c
Exemple #5 Exemple d'utilisation de l'opérateur combiné avec usort().
L'opérateur combiné permet une comparaison directe de valeurs composées sur
plusieurs axes.
Dans l'exemple suivant, $people
est trié par nom de famille,
puis par prénom si le nom de famille correspond.
<?php
$people[0] = ['first' => 'Adam', 'last' => 'West'];
$people[1] = ['first' => 'Alec', 'last' => 'Baldwin'];
$people[2] = ['first' => 'Adam', 'last' => 'Baldwin'];
function sorter(array $a, array $b) {
return [$a['last'], $a['first']] <=> [$b['last'], $b['first']];
}
usort($people, 'sorter');
foreach ($people as $person) {
print $person['last'] . ', ' . $person['first'] . PHP_EOL;
}
?>
L'exemple ci-dessus va afficher :
Baldwin, Adam Baldwin, Alec West, Adam
As the documentation says, the comparison function needs to return an integer that is either "less than, equal to, or greater than zero". There is no requirement to restrict the value returned to -1, 0, 1.
<?php
usort($array, function($a, $b) {
if($a->integer_property > $b->integer_property) {
return 1;
}
elseif($a->integer_property < $b->integer_property) {
return -1;
}
else {
return 0;
}
});
?>
can be simplified to
<?php
usort($array, function($a, $b) {
return $a->integer_property - $b->integer_property;
});
?>
This of course applies to any comparison function that calculates an integer "score" for each of its arguments to decide which is "greater".
If you need to use usort with a key in the calling method, I wrote this as a utility:
<?php
function usort_comparison($obj, $method, $key) {
$usorter = &new Usort($obj, $method, $key);
return array($usorter, "sort");
}
class Usort {
function __construct($obj, $method, $key) {
$this->obj = $obj;
$this->method = $method;
$this->key = $key;
}
function sort($a, $b) {
return call_user_func_array(array($this->obj, $this->method), array($a, $b, $this->key));
}
}
?>
<?php
require_once("util/usort.php");
class Foo {
$items = array(FooBar(13), FooBar(2));
public function sorter() {
usort($this-items, usort_comparison("Foo", "_cmp", "item"));
}
public static function _cmp($a, $b, $key) {
return strcasecmp($a->$key, $b->$key);
}
}
class FooBar {
public $item;
function __construct($val) {
$this->item = $val;
}
}
?>
~ simple example... but in the way I need to use it was the key was used in a switch statement to choose the different member of the object to compare against dynamically (as in, sort by x or y or z)
If you want to sort an array according to another array acting as a priority list, you can use this function.
<?php
function listcmp($a, $b)
{
global $order;
foreach($order as $key => $value)
{
if($a==$value)
{
return 0;
break;
}
if($b==$value)
{
return 1;
break;
}
}
}
$order[0] = "first";
$order[1] = "second";
$order[2] = "third";
$array[0] = "second";
$array[1] = "first";
$array[2] = "third";
$array[3] = "fourth";
$array[4] = "second";
$array[5] = "first";
$array[6] = "second";
usort($array, "listcmp");
print_r($array);
?>
Needed a date sort and I didn't know if one was available so I wrote one. Maybe it'll help someone:
<?php
function DateSort($a,$b,$d="-") {
if ($a == $b) {
return 0;
} else { //Convert into dates and compare
list($am,$ad,$ay)=split($d,$a);
list($bm,$bd,$by)=split($d,$b);
if (mktime(0,0,0,$am,$ad,$ay) < mktime(0,0,0,$bm,$bd,$by)) {
return -1;
} else {
return 1;
}
}
}
?>
$d is the delimeter
Instead of doing :
<?php $strc = strcmp( strtolower($a[$f]), strtolower($b[$f]) ); ?>
you could do this :
<?php $strc = strcasecmp( $a[$f], $b[$f] ); ?>
which is more efficient and is does case insensitive comparison according to the current locale.
This is a simple way to sort based on a "priority list":
<?php
$order = [1,3,0,2];
$arr = [
[ 'id' => 0 ],
[ 'id' => 1 ],
[ 'id' => 2 ],
[ 'id' => 3 ],
];
uasort(
$arr,
function ($a, $b) use ($order) {
return array_search($a['id'], $order) <=> array_search($b['id'], $order);
}
);
print_r($arr);
?>
This will return:
Array
(
[1] => Array
(
[id] => 1
)
[3] => Array
(
[id] => 3
)
[0] => Array
(
[id] => 0
)
[2] => Array
(
[id] => 2
)
)
Note that if you have a value in $arr that is not on the $order list, you will need additional checks since the array_search function returns FALSE for undefined indexes.
to sort with numeric and empty values and have the smallest on top:
<?php
usort($list, function($a, $b) {
if( $a == null && $b != null ) return 1;
if( $a != null && $b == null ) return -1;
return $a > $b ? 1 : -1;
});
?>
returns
1
2
3
null
null
null
In case anyone is interested, comparative timings over 100000000 runs
Based on comparing integers (500 and 501)
Spaceship:4
()?: operator:10
Subtraction:2
Based on comparing floats (500.1 and 501.3) (caveats noted)
Spaceship:5
()?: operator:9
Subtraction:3
Based on comparing strings ("five" and "four")
Spaceship:7
()?: operator:17
(Subtraction obviously not available)
Note: a dummy run was done with an empty loop and the elapsed time for this was subtracted from each of the above times so that they reflect ONLY the time to do the comparisons. As for significance. unless you are doing very large numbers of comparisons where spaceships are the order of the day, the difference is insignificant.
when using usort to refer to a function inside a class i have succesfully used:
<?php usort($myarray,array($this,"cmp")); ?>
I needed a sort method that would sort strings but take note of any numbers and would compare them as number. I also want to ignore any non alphanumerical characters.
Eg.
Slot 1 Example
Slot 10 Example
Slot 2 Example
Should infact be
Slot 1 Example
Slot 2 Example
Slot 10 Example
<?php
function sort_with_numbers($a , $b) {
$a = explode(' ',$a);
$b = explode(' ',$b);
$size = min(count($a), count($b));
for($index =0; $index < $size; ++$index) {
$a1 = ereg_replace("[^A-Za-z0-9]", "",$a[$index]);
$b1 = ereg_replace("[^A-Za-z0-9]", "",$b[$index]);
$equal = 0;
if (is_numeric($a1) && is_numeric($b1)) {
$equal = $a1 - $b1;
} else {
$equal = strcasecmp($a1,$b1);
}
if ($equal < 0) {
return -1;
}
if ($equal > 0) {
return 1;
}
}
return count($a) - count($b);
}
?>
A sort function to sort elements by a reference order.
function sort_by_reference(array $array_to_sort, array $reference_array): array {
usort($array_to_sort, function($a, $b) use ($reference_array) {
$pos_a = array_search($a, $reference_array);
$pos_b = array_search($b, $reference_array);
return $pos_a - $pos_b;
});
return $array_to_sort;
}
// Example usage
$reference_array = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
$array_to_sort = ["three", "one", "seven", "four", "ten"];
$sorted_array = sort_by_reference($array_to_sort, $reference_array);
// Print the result to verify the sorting
print_r($sorted_array);
```
Array
(
[0] => one
[1] => three
[2] => four
[3] => seven
[4] => ten
)
```