PHP Conference Japan 2024

usort

(PHP 4, PHP 5, PHP 7, PHP 8)

usort使用使用者定義的比較函式,依值排序陣列

描述

usort(array &$array, callable $callback): true

使用使用者提供的比較函式來決定順序,將 array 依值原地排序。

注意:

如果兩個成員比較為相等,它們會保留原始順序。 在 PHP 8.0.0 之前,它們在排序陣列中的相對順序是未定義的。

注意此函式會將新索引鍵指定給 array 中的元素。 它會移除任何可能已指定的現有索引鍵,而不僅僅是重新排序索引鍵。

參數

array

輸入陣列。

callback

如果第一個引數被認為分別小於、等於或大於第二個引數,則比較函式必須傳回小於、等於或大於零的整數。

callback(mixed $a, mixed $b): int
警告

從比較函式傳回非整數值,例如 float,將導致回呼函式的傳回值在內部轉換為 int。 因此,例如 0.990.1 等值都將轉換為整數值 0,這會將這些值視為相等。

傳回值

一律傳回 true

變更日誌

版本 描述
8.2.0 傳回類型現在為 true;先前為 bool
8.0.0 如果 callback 預期以參考方式傳遞參數,則此函式現在會發出 E_WARNING

範例

範例 1 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";
}
?>

以上範例將會輸出

0: 1
1: 2
2: 3
3: 5
4: 6

太空船運算子可用於進一步簡化內部比較。

<?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";
}
?>

注意:

顯然,在這個簡單的情況下,sort() 函式會更適合。

範例 2 usort() 範例,使用多維陣列

<?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";
}
?>

在排序多維陣列時,$a$b 包含對陣列第一個索引的參考。

以上範例將會輸出

$fruits[0]: apples
$fruits[1]: grapes
$fruits[2]: lemons

範例 3 usort() 範例,使用物件的成員函式

<?php
class TestObj {
private
string $name;

function
__construct($name)
{
$this->name = $name;
}

/* 這是一個靜態比較函式: */
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";
}
?>

以上範例將會輸出

b
c
d

範例 #4 使用usort()閉包來排序多維陣列

<?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";
}
?>

以上範例將會輸出

y, a
x, b
z, c

範例 #5 使用太空船運算符的 usort() 範例

太空船運算符允許跨多個軸直接比較複合值。以下範例將依姓氏排序 $people,如果姓氏相同則依名字排序。

<?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;
}
?>

以上範例將會輸出

Baldwin, Adam
Baldwin, Alec
West, Adam

參見

新增註解

使用者貢獻的註解 11 則註解

21
Hayley Watson
11 年前
如同文件所說,比較函式需要回傳一個整數,該整數的值必須為「小於、等於或大於零」。並未要求回傳的值必須限制為 -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;
}
});
?>

可以簡化為

<?php
usort
($array, function($a, $b) {
return
$a->integer_property - $b->integer_property;
});
?>

當然,這適用於任何為其每個參數計算整數「分數」以決定哪個「更大」的比較函數。
12
luke dot semerau at gmail dot com
15 年前
如果您需要在呼叫方法中使用帶有鍵值的 usort,我將其寫成一個實用程式
<?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;
}
}

?>

~ 簡單的範例... 但在我需要使用的方式中,關鍵字是用在 switch 語句中,以動態選擇要比較的物件的不同成員(例如,依 x 或 y 或 z 排序)。
14
mkr at binarywerks dot dk
22 年前
如果您想根據另一個充當優先順序列表的陣列來排序陣列,您可以使用此函數。

<?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);
?>
8
derek at luddite dot net
24 年前
需要日期排序,而且我不確定是否有可用的排序方法,所以我寫了一個。也許對某些人有幫助

<?php
function DateSort($a,$b,$d="-") {
if (
$a == $b) {
return
0;
} else {
// 轉換成日期並比較
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 是分隔符號
5
sydney at totoche dot org
18 年前
與其這樣做

<?php $strc = strcmp( strtolower($a[$f]), strtolower($b[$f]) ); ?>

您可以這樣做

<?php $strc = strcasecmp( $a[$f], $b[$f] ); ?>

這樣效率更高,而且會根據目前的語系進行不區分大小寫的比較。
2
gus dot antoniassi at gmail dot com
5 年前
這是一種根據「優先順序列表」進行排序的簡單方法

<?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);

?>

這將會返回

陣列
(
[1] => 陣列
(
[id] => 1
)

[3] => 陣列
(
[id] => 3
)

[0] => 陣列
(
[id] => 0
)

[2] => 陣列
(
[id] => 2
)

)

請注意,如果您的 $arr 中有不在 $order 列表中的值,您將需要額外的檢查,因為 array_search 函數會為未定義的索引返回 FALSE。
4
inigo dot grimbergen at gmail dot com
7 年前
為了使用數值和空值進行排序,並將最小的放在最上面
<?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;
});
?>
返回
1
2
3
null
null
null
3
andi_mclean at ntlworld dot com
12 年前
我需要一個排序方法,該方法可以對字串進行排序,但會注意任何數字並將它們作為數字進行比較。我也想忽略任何非字母數字字元。

例如。
Slot 1 Example
Slot 10 Example
Slot 2 Example

實際上應該是
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);
}
?>
1
chris at candm dot org dot uk
5 年前
如果有人有興趣,以下是在 100000000 次執行次數下的比較計時:
基於比較整數(500 和 501):
太空船運算子:4
()?: 運算子:10
減法:2

基於比較浮點數(500.1 和 501.3)(已注意警告):
太空船運算子:5
()?: 運算子:9
減法:3

基於比較字串("five" 和 "four"):
太空船運算子:7
()?: 運算子:17
(顯然無法使用減法)

注意:使用空迴圈進行了虛擬執行,並從上述每個時間中減去了此經過的時間,以便它們僅反映進行比較的耗時。至於顯著性,除非您正在執行非常大量的比較(其中太空船運算子是首選),否則差異並不顯著。
2
bo at erichsen dot com
23 年前
當使用 usort 來引用類別內的函式時,我已成功使用過

<?php usort($myarray,array($this,"cmp")); ?>
1
rh at 20i dot com
3 個月前
一個用於根據參考順序排序元素的排序函式。

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;
}

// 範例用法
$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_r($sorted_array);

```
陣列
(
[0] => one
[1] => three
[2] => four
[3] => seven
[4] => ten
)
```
To Top