[編者註:以下評論可能與事實不符]
uksort 只能在英國使用
<?php
if($country=="UK"){
uksort();
}else{
echo "您必須住在英國才能使用 uksort()。";
}
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
uksort — 使用使用者自訂的比較函式依鍵值排序陣列
使用使用者提供的比較函式來決定順序,並以鍵值排序 array
(原地排序)。
注意:
如果兩個成員比較結果相等,它們會保留其原始順序。在 PHP 8.0.0 之前,它們在排序後陣列中的相對順序未定義。
注意:
重設陣列的內部指標到第一個元素。
array
輸入的陣列。
callback
比較函式必須回傳一個整數。若第一個參數分別小於、等於或大於第二個參數,則回傳值應小於零、等於零或大於零。
總是返回 true
。
範例 #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
[編者註:以下評論可能與事實不符]
uksort 只能在英國使用
<?php
if($country=="UK"){
uksort();
}else{
echo "您必須住在英國才能使用 uksort()。";
}
?>
使用排序規則排序,以便正確顯示變音符號
uksort($retval, array(Collator::create( 'de_DE' ), 'compare'));
(關於按類別中的屬性對物件陣列進行排序 - 靈感來自 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 />";
}
?>
請注意,這可能不是世界上最快的東西,而且它還沒有經過很多測試,但我希望它對某些人有用。
關於 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;
...
?>
關於上述的遞迴排序函式
一般來說,任何遞迴都可以用簡單的迭代重新實作。在這個特定情況下,使用遞迴來比較字串會對效能造成巨大的影響,而一個簡單的迴圈就足夠了,而且速度更快、更簡單。
遞迴只有在簡化程式碼或簡化您對概念的理解時才有好處。前面的例子兩者都沒有做到,尤其是在每次迭代中做了很多重複的事情,例如賦值字元順序常數、將其重建為陣列等等。
例如,字串比較可以這樣寫:
function str_compare($a,$b) {
$order="aA??bBcCčČ..."; // 通常更長 & 沒有 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 中的字元會失效。修復它應該相當簡單。
需要一個不區分大小寫的鍵排序函式嗎?我需要,但找不到,所以…
<?php
function insensitive_uksort($a,$b) {
return strtolower($a)<strtolower($b);
}
uksort($arr, "insensitive_uksort");
?>
這是一個小型且非常快速的物件,用於處理多維陣列按鍵排序。
<?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
)
如果您需要定期依成績排序(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
)
這對許多人來說可能很明顯,但只是為了幫助其他試圖在類別中使用它的人。在類別內部,您可以在 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);
}
}
使用 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;
}
不要使用 uksort($array, "strnatcasecmp"); ... 使用 ksort($array, SORT_NATURAL|SORT_FLAG_CASE);
...
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 );
...
以下程式碼允許您按照 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)
要使用更複雜的比較函數,可以使用物件實例方法的回呼。
例如,以下將採用鍵與 $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 ) ;
我需要能夠排序包含數字的字串,例如:
"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);
}