PHP Conference Japan 2024

uksort

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

uksort使用使用者自訂的比較函式依鍵值排序陣列

說明

uksort(陣列 &$array, 可呼叫 $callback): true

使用使用者提供的比較函式來決定順序,並以鍵值排序 array(原地排序)。

注意:

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

注意:

重設陣列的內部指標到第一個元素。

參數

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 uksort() 範例

<?php
function cmp($a, $b)
{
$a = preg_replace('@^(a|an|the) @', '', $a);
$b = preg_replace('@^(a|an|the) @', '', $b);
return
strcasecmp($a, $b);
}

$a = array("John" => 1, "the Earth" => 2, "an apple" => 3, "a banana" => 4);

uksort($a, "cmp");

foreach (
$a as $key => $value) {
echo
"$key: $value\n";
}
?>

上述範例將輸出:

an apple: 3
a banana: 4
the Earth: 2
John: 1

另請參閱

新增註釋

使用者貢獻的註釋 17 則註釋

PHPUser
9 年前
[編者註:以下評論可能與事實不符]

uksort 只能在英國使用
<?php
if($country=="UK"){
uksort();
}else{
echo
"您必須住在英國才能使用 uksort()。";
}
?>
ingo at example dot test
10 年前
使用排序規則排序,以便正確顯示變音符號

uksort($retval, array(Collator::create( 'de_DE' ), 'compare'));
fabriceb at gmx dot net
20 年前
(關於按類別中的屬性對物件陣列進行排序 - 靈感來自 usort 函數中的 webmaster at zeroweb dot org)
我使用類別作為查詢資料庫記錄的抽象,並使用物件陣列來儲存具有一對多關係的記錄。例如,“family”類別具有以物件陣列形式儲存的家庭成員。每個物件都代表資料庫中與家庭相關的記錄(通過其 familyId)。

為了識別成員,我使用他們的 memberId 作為陣列的鍵,例如 $family->members[$memberId]。
要在使用資料庫查詢擷取家庭成員後對其進行排序,可以使用 _objSort 和 sortMembers 函數,這些函數將使用其屬性按鍵對“members”陣列進行排序(由於篇幅原因,我沒有包含用於開啟記錄的方法)
<?php
class familyMember
{
var
$memberId;
var
$familyId;
var
$firstName;
var
$age;
var
$hairColor;
// ...
}

class
family
{
var
$familyId;
var
$name;
var
$members = array(); // array of familyMember objects
var $sortFields = array();
var
$sortDirections = array();
// ...
function _objSort(&$a, &$b, $i = 0)
{
$field = $this->sortFields[$i];
$direction = $this->sortDirections[$i];

$diff = strnatcmp($this->details[$a]->$field, $this->details[$b]->$field) * $direction;
if (
$diff == 0 && isset($this->sortFields[++$i]))
{
$diff = $this->_objSort($a, $b, $i);
}

return
$diff;
}

function
sortMembers($sortFields)
{
$i = 0;
foreach (
$sortFields as $field => $direction)
{
$this->sortFields[$i] = $field;
$direction == "DESC" ? $this->sortDirections[$i] = -1 : $this->sortDirections[$i] = 1;
$i++;
}

uksort($this->details, array($this, "_objSort"));

$this->sortFields = array();
$this->sortDirections = array();
}
}
// open a family
$familyId = 5;
$family = new family($familyId);
$family->open(); // this will also fetch all members

// sort members by 3 fields
$family->sortMembers(array("firstName" => "ASC", "age" => "DESC", "hairColor" => "ASC"));
// output all family members
foreach ($family->members as $member)
{
echo
$member->firstName." - ".$member->age." - ".$member->hairColor."<br />";
}
?>

請注意,這可能不是世界上最快的東西,而且它還沒有經過很多測試,但我希望它對某些人有用。
mdsky at web dot de
14 年前
無需自定義函數即可不區分大小寫

uksort($array, "strnatcasecmp");
aleczapka at gmx dot net
19 年前
關於 array_sorter 類別的一點說明。
它無法正確處理例如來自 mysql 的日期,例如 20041206105350,因為您無法將此類數字轉換為整數。要修復它,請從程式碼中移除 intval()。如果變數是數字,它將在不轉換為 int 的情況下工作。以下是修復方法。

<?php
....
if (
$a == $b)
return
0;
if (
$this->sasc)
return (
$a > $b) ? 1 : -1;
else
return (
$a > $b) ? -1 : 1;
...
?>
guss at typo dot co dot il
20 年前
關於上述的遞迴排序函式
一般來說,任何遞迴都可以用簡單的迭代重新實作。在這個特定情況下,使用遞迴來比較字串會對效能造成巨大的影響,而一個簡單的迴圈就足夠了,而且速度更快、更簡單。
遞迴只有在簡化程式碼或簡化您對概念的理解時才有好處。前面的例子兩者都沒有做到,尤其是在每次迭代中做了很多重複的事情,例如賦值字元順序常數、將其重建為陣列等等。

例如,字串比較可以這樣寫:
function str_compare($a,$b) {
$order="aA??bBcC&#269;&#268;..."; // 通常更長 & 沒有 HTML 實體
$default = strlen($a) - strlen($b);
$minlen = strlen($a) < strlen($b) ? strlen($a) : strlen($b);
for ($i = 0; $i < $minlen; $i++) {
$pos_a=strpos($order,$a[$i]);
$pos_b=strpos($order,$b[$i]);
if ($pos_a != $pos_b)
return $pos_a - $pos_b;
}
return $default;
}

這樣更簡單也更快。
請注意,上述函式對於未列在 $order 中的字元會失效。修復它應該相當簡單。
contacto at hardcode dot com dot ar
15 年前
需要一個不區分大小寫的鍵排序函式嗎?我需要,但找不到,所以…

<?php
function insensitive_uksort($a,$b) {
return
strtolower($a)<strtolower($b);
}
uksort($arr, "insensitive_uksort");
?>
aleczapka at gmx dot net
19 年前
這是一個小型且非常快速的物件,用於處理多維陣列按鍵排序。
<?php
/**
* Handles multidimentional array sorting by a key (not recursive)
*
* @author Oliwier Ptak <aleczapka at gmx dot net>
*/
class array_sorter
{
var
$skey = false;
var
$sarray = false;
var
$sasc = true;

/**
* Constructor
*
* @access public
* @param mixed $array array to sort
* @param string $key array key to sort by
* @param boolean $asc sort order (ascending or descending)
*/
function array_sorter(&$array, $key, $asc=true)
{
$this->sarray = $array;
$this->skey = $key;
$this->sasc = $asc;
}

/**
* Sort method
*
* @access public
* @param boolean $remap if true reindex the array to rewrite indexes
*/
function sortit($remap=true)
{
$array = &$this->sarray;
uksort($array, array($this, "_as_cmp"));
if (
$remap)
{
$tmp = array();
while (list(
$id, $data) = each($array))
$tmp[] = $data;
return
$tmp;
}
return
$array;
}

/**
* Custom sort function
*
* @access private
* @param mixed $a an array entry
* @param mixed $b an array entry
*/
function _as_cmp($a, $b)
{
//since uksort will pass here only indexes get real values from our array
if (!is_array($a) && !is_array($b))
{
$a = $this->sarray[$a][$this->skey];
$b = $this->sarray[$b][$this->skey];
}

//if string - use string comparision
if (!ctype_digit($a) && !ctype_digit($b))
{
if (
$this->sasc)
return
strcasecmp($a, $b);
else
return
strcasecmp($b, $a);
}
else
{
if (
intval($a) == intval($b))
return
0;

if (
$this->sasc)
return (
intval($a) > intval($b)) ? -1 : 1;
else
return (
intval($a) > intval($b)) ? 1 : -1;
}
}

}
//end of class
?>

範例 $input_array

陣列
(
[0] => 陣列
(
[id] => 961
[uid] => 29
[gid] => 12
[parent_id] => 147
[created] => 20041206105350
[modified] => 20041206110702
)

[1] => 陣列
(
[id] => 41
[uid] => 29
[gid] => 12
[parent_id] => 153
[created] => 20041025154009
[modified] => 20041206105532
)

[2] => 陣列
(
[id] => 703
[uid] => 29
[gid] => 12
[parent_id] => 419
[created] => 20041025154132
[modified] => 20041027150259
)

使用方法範例
<?php
函式 multi_sort(&$array, $key, $asc=true)
{
$sorter = new array_sorter($array, $key, $asc);
return
$sorter->sortit();
}
//依 parent_id 遞減排序
$my_array = multi_sort($input_array, "parent_id", false);
?>

結果陣列將會是
陣列
(

[0] => 陣列
(
[id] => 703
[uid] => 29
[gid] => 12
[parent_id] => 419
[created] => 20041025154132
[modified] => 20041027150259
)

[1] => 陣列
(
[id] => 41
[uid] => 29
[gid] => 12
[parent_id] => 153
[created] => 20041025154009
[modified] => 20041206105532
)

[2] => 陣列
(
[id] => 961
[uid] => 29
[gid] => 12
[parent_id] => 147
[created] => 20041206105350
[modified] => 20041206110702
)
brian dot short at gmail dot com
15 年前
如果您需要定期依成績排序(A、A+、D- 等),這裡有一個比較函式,它會使用不區分大小寫的方式比較字串,除非它找到一個成績,在這種情況下,它會正確地將「加號」成績排在第一位,未標記的成績排在第二位,「減號」成績排在最後。

<?php
function cmp($a, $b)
{
$a = preg_replace('@^(a|an|the) @', '', $a);
$b = preg_replace('@^(a|an|the) @', '', $b);

//special code for grades
if (strpos( $a, "+") !== false || strpos( $b, "+") !== false ||
strpos( $a, "-") !== false || strpos( $b, "-") !== false ){

$substrA = substr($a, 0, 1);
$substrB = substr($b, 0, 1);

$modifierA = (strlen($a) == 2) ? substr($a, 1, 1) : "";
$modifierB = (strlen($b) == 2) ? substr($b, 1, 1) : "";

if (
$substrA == $substrB){
//figure out plusses and minuses.
if ($modifierA == "+"){
return -
1;
} else if (
$modifierB == "+"){
return
1;
}

if (
$modifierA == "-"){
return
1;
} else if (
$modifierB == '-'){
return -
1;
}
} else {
return
strcasecmp($a, $b);
}

}
return
strcasecmp($a, $b);
}

$grades = array(
"C+" => 13 ,
"C" => 10 ,
"D+" => 8 ,
"B+" => 7 ,
"C-" => 6 ,
"A-" => 5 ,
"F" => 5 ,
"B" => 4 ,
"B-" => 4 ,
"D" => 3 ,
"D-" => 3 ,
"A+" => 1
);

uksort($grades, "cmp");
?>

結果:陣列
(
[A+] => 1
[A-] => 5
[B+] => 7
[B] => 4
[B-] => 4
[C+] => 13
[C] => 10
[C-] => 6
[D+] => 8
[D] => 3
[D-] => 3
[F] => 5
)
smcbride at msn dot com
3 年前
這對許多人來說可能很明顯,但只是為了幫助其他試圖在類別中使用它的人。在類別內部,您可以在 uksort() 中使用 self:: 作為函式的前綴,它就會正常運作。此外,如果它在另一個被包含的類別中,您可以使用類別名稱作為前綴。

class someclass {
private function ArraySortCMPIP($a, $b) {
$a = ip2long($a);
$b = ip2long($b);

if ($a == $b) return 0;
return ($a < $b) ? -1 : 1;
}

// 輸出
public function PrintResults() {
uksort($this->someIPAddressArray, 'self::ArraySortCMPIP');
print_r($this->someIPAddressArray);
}
}
jg at delegation dot ca
19 年前
使用 uksort 排序日期

function datediff($a, $b) {


$a = date('U',$a);
$b = date('U',$b);

if ($a == $b) $r = 0;
else $r = ($a > $b) ? 1: -1;

return $r;
}
DimeCadmium
6 年前
不要使用 uksort($array, "strnatcasecmp"); ... 使用 ksort($array, SORT_NATURAL|SORT_FLAG_CASE);
Jimomighty
19 年前
...

function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}

function uksort_tree ( &$array )
{
// [PHP5] foreach ( $array as &$value )
foreach ( $array as $key => $value )
{
if ( is_array ( $value ) )
{
// [PHP5] uksort_tree ( $value );
uksort_tree ( $array[$key] );
}
}

uksort( $array, "cmp" );
}

uksort_tree( $myEntryArray );

...
webmaster at kik-it at N0SP4M dot com
20 年前
以下程式碼允許您按照 array_B 鍵的順序排序 array_A,原始鍵和值保持關聯。

<?

//主要函式
Function SortArrayAKeysLikeArrayBKeys(&$TheArrayToSort){
uksort($TheArrayToSort,"SortArrayAKeysLikeArrayBKeys_cmp");
}

//自訂比較函式
Function SortArrayAKeysLikeArrayBKeys_cmp($a,$b){
global $TheArrayOrder;
$PosA=KeyPosInArray($a,$TheArrayOrder);
$PosB=KeyPosInArray($b,$TheArrayOrder);
如果 ($PosA==$PosB){返回 0;}否則{返回 ($PosA > $PosB ? 1 : -1);}
}

//我的 key 在我的陣列中的哪裡
函數 KeyPosInArray($Key,$Array){
$i=0;
$Pos=99999999;
如果($Array){
foreach($Array as $K => $V){
$i++;
如果($K==$Key){
$Pos=$i;
跳出;
}
}
}
返回 $Pos;
}

//您想要排序的陣列
$AnyArrayToSort['age']='19';
$AnyArrayToSort['ville']='rennes';
$AnyArrayToSort['website']='kik-it.com';
$AnyArrayToSort['region']='bretagne';
$AnyArrayToSort['code_postal']='35200';
$AnyArrayToSort['Nom']='Fred';

//具有正確鍵/值順序的陣列
$TheArrayOrder['Nom']='Whatever';
$TheArrayOrder['age']='Anything';
$TheArrayOrder['region']='What u want';
$TheArrayOrder['ville']='Something';
$TheArrayOrder['code_postal']='Nothing';

//排序前
print_r($AnyArrayToSort);
echo "<br>";
//我們排序
SortArrayAKeysLikeArrayBKeys($AnyArrayToSort);
echo "<br>";
//排序後
print_r($AnyArrayToSort);
?>

將會印出

陣列 ( [age] => 19 [ville] => rennes [website] => kik-it.com [region] => bretagne [code_postal] => 35200 [Nom] => Fred )

陣列 ( [Nom] => Fred [age] => 19 [region] => bretagne [ville] => rennes [code_postal] => 35200 [website] => kik-it.com )

未列在 $TheArrayOrder 中的鍵將會出現在排序後陣列的末尾(僅限於鍵位置 < 99999999 ;o)
ignatius dot reilly at free dot fr
21 年前
要使用更複雜的比較函數,可以使用物件實例方法的回呼。
例如,以下將採用鍵與 $reference 相同的陣列 $arr,並重新排序 $arr,使鍵的出現順序與 $reference 中的順序相同。

類別 kcmp {
變數 $reference ;
函數 kcmp( $reference ) {
$this->reference = $reference ;
}
函數 kcompare( $a, $b ) {
$keys = array_keys( $this->reference ) ;
$position_a = array_search( $a, $keys ) ;
$position_b = array_search( $b, $keys ) ;
返回 $position_a < $position_b ? -1 : 1 ;
}
}

$reference = 陣列(
"k2" => "a2",
"k3" => "a3",
"k1" => "a1"
) ;
$arr = 陣列(
"k1" => "b1",
"k2" => "b2",
"k3" => "b3"
) ;
print_r( $arr ) ;
uksort( $arr, 陣列( new kcmp( $reference ), "kcompare" ) ) ;
print_r( $arr ) ;
andi at example dot com
8 年前
我需要能夠排序包含數字的字串,例如:

"Slot 1 name"
"Slot 2 name"
"Slot 10 name"

使用一般的字串比較,"Slot 10 name" 會出現在 "Slot 2 name" 之前,所以我寫了一個小函數,它會考慮數字來比較字串。可能有一些邊緣情況需要考慮。

函數 strCmpWithNumbers( $a, $b) {
// 將字串拆分成單詞。
$a = explode(' ',$a);
$b = explode(' ',$b);
$loop = 0;
do {
// 從每個項目中獲取第一個單詞
$ta = Utils::gvfa($a, $loop);
$tb = Utils::gvfa($b, $loop);

如果 (isset($ta)) {
如果 (isset($tb)) {
如果 (is_numeric($ta)) {
如果 ($ta != $tb) {
返回 $ta - $tb;
}
} 否則 {
$val = strcasecmp($ta, $tb);
如果 ($val != 0) {
返回 $val;
}
}
} 否則 {
返回 1; // a 已設定,但 b 沒有
}
} 否則 {
返回 isset($b);
}
$loop +=1;
} while (true);
}
匿名
9 年前
對於鍵值已知的關聯式陣列,可以使用 switch 陳述式在回呼函式中輕鬆進行客製化排序

注意:可以事先使用 ksort 來確保預期的結果

ksort($array);

uksort($array, function ($a) {
switch($a) {
case 'pepperoni':
return 0;
case 'beef':
return 1;
case 'chicken':
return 2;
case 'ham':
return 3;
case 'vegetarian':
return 4;
}
});
To Top