PHP 日本大会 2024

uksort

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

uksort使用用户自定义比较函数对数组按键排序

描述

uksort(数组 &$array, 可调用 $callback): true

使用用户提供的比较函数来确定顺序,对 array 按键进行就地排序。

注意:

如果两个成员比较结果相等,则保留其原始顺序。在 PHP 8.0.0 之前,它们在排序数组中的相对顺序是不确定的。

注意:

将数组的内部指针重置为第一个元素。

参数

array

输入数组。

callback

比较函数必须返回一个整数,如果第一个参数分别小于、等于或大于第二个参数,则返回小于、等于或大于零。

callback(混合 $a, 混合 $b): int
警告

从比较函数返回*非整数*值(例如 浮点数)将导致回调返回值内部转换为 整数。因此,诸如 0.990.1 之类的值都将转换为整数 0,这将把这些值视为相等。

返回值

始终返回 true

变更日志

版本 描述
8.2.0 返回值现在为 true;之前为 布尔值
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 条注释

580
PHPUser
9 年前
[编辑注:以下评论可能不准确]

uksort 只能在英国使用
<?php
if($country=="UK"){
uksort();
}else{
echo
"您必须居住在英国才能使用 uksort().";
}
?>
9
ingo at example dot test
10 年前
带排序规则的排序,以便正确处理变音符号

uksort($retval, array(Collator::create( 'de_DE' ), 'compare'));
12
fabriceb at gmx dot net
20 年前
(关于按类中的属性对对象数组进行排序 - 灵感来自 usort 函数中的 webmaster at zeroweb dot org)
我使用类作为查询数据库记录的抽象,并使用对象数组来存储具有 1 对 n 关系的记录。例如,“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(); // familyMember 对象数组
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();
}
}
// 打开一个家庭
$familyId = 5;
$family = new family($familyId);
$family->open(); // 这也会获取所有成员

// 按三个字段排序成员
$family->sortMembers(array("firstName" => "ASC", "age" => "DESC", "hairColor" => "ASC"));
// 输出所有家庭成员
foreach ($family->members as $member)
{
echo
$member->firstName." - ".$member->age." - ".$member->hairColor."<br />";
}
?>

请注意,这可能不是世界上最快的,而且还没有经过太多测试,但我希望它对某些人有用。
4
mdsky at web dot de
14年前
不区分大小写,无需自定义函数

uksort($array, "strnatcasecmp");
1
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;
...
?>
3
guss at typo dot co dot il
20 年前
关于上面递归排序函数
一般来说,任何递归都可以使用简单的迭代重新实现。在这种特定情况下,使用递归来比较字符串会产生巨大的性能影响,而简单的循环就足够了,而且更快更简单。
递归只有在简化代码或对概念的理解时才有效。前面的示例两者都没有做到,尤其因为它在每次迭代中都做了很多重复的事情,例如分配字符顺序常量,将其重建成数组等等。

例如,字符串比较可以这样写:
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 中的字符,上述函数将失效。修复它应该相当容易。
2
contacto at hardcode dot com dot ar
15年前
需要一个不区分大小写的按键排序函数吗?我需要,但找不到,所以

<?php
function insensitive_uksort($a,$b) {
return
strtolower($a)<strtolower($b);
}
uksort($arr, "insensitive_uksort");
?>
2
aleczapka at gmx dot net
19年前
这是一个用于处理按键对多维数组进行排序的小而快速的类。
<?php
/**
* 处理多维数组按键排序(非递归)
*
* @author Oliwier Ptak <aleczapka at gmx dot net>
*/
class array_sorter
{
var
$skey = false;
var
$sarray = false;
var
$sasc = true;

/**
* 构造函数
*
* @access public
* @param mixed $array 要排序的数组
* @param string $key 排序依据的数组键
* @param boolean $asc 排序顺序 (升序或降序)
*/
function array_sorter(&$array, $key, $asc=true)
{
$this->sarray = $array;
$this->skey = $key;
$this->sasc = $asc;
}

/**
* 排序方法
*
* @access public
* @param boolean $remap 如果为 true,则重新索引数组以重写索引
*/
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;
}

/**
* 自定义排序函数
*
* @access private
* @param mixed $a 数组条目
* @param mixed $b 数组条目
*/
function _as_cmp($a, $b)
{
//由于 uksort 只会传递索引,因此从我们的数组中获取真实值
if (!is_array($a) && !is_array($b))
{
$a = $this->sarray[$a][$this->skey];
$b = $this->sarray[$b][$this->skey];
}

//如果是字符串 - 使用字符串比较
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;
}
}

}
//类结束
?>

示例 $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
function 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
)
1
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);

//成绩的特殊代码
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){
//确定加号和减号。
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
)
0
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);
}
}
1
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;
}
0
DimeCadmium
6年前
不要使用`uksort($array, "strnatcasecmp");`……使用`ksort($array, SORT_NATURAL|SORT_FLAG_CASE);`
0
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 );

...
0
webmaster at kik-it at N0SP4M dot com
20 年前
以下代码允许你按照数组B的键的顺序对数组A进行排序,原始键和值保持关联。

<?

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

//自定义比较函数
Function SortArrayAKeysLikeArrayBKeys_cmp($a,$b){
global $TheArrayOrder;
$PosA=KeyPosInArray($a,$TheArrayOrder);
$PosB=KeyPosInArray($b,$TheArrayOrder);
if ($PosA==$PosB){return 0;}else{return ($PosA > $PosB ? 1 : -1);}
}

//我的键在我的数组中的位置
Function KeyPosInArray($Key,$Array){
$i=0;
$Pos=99999999;
if($Array){
foreach($Array as $K => $V){
$i++;
if($K==$Key){
$Pos=$i;
break;
}
}
}
return $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);
?>

将会输出

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

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

在`$TheArrayOrder`中未列出的键将出现在已排序数组的末尾(仅当键位置 < 99999999 时 ;o)
0
ignatius dot reilly at free dot fr
21年前
要使用更复杂的比较函数,可以使用回调函数来调用对象实例的方法。
例如,以下代码将采用一个数组`$arr`,其键与`$reference`的键相同,并重新排序`$arr`,以便键的顺序与`$reference`中的顺序相同。

class kcmp {
var $reference ;
function kcmp( $reference ) {
$this->reference = $reference ;
}
function kcompare( $a, $b ) {
$keys = array_keys( $this->reference ) ;
$position_a = array_search( $a, $keys ) ;
$position_b = array_search( $b, $keys ) ;
return $position_a < $position_b ? -1 : 1 ;
}
}

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

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

使用普通的字符串比较,"Slot 10 name" 会出现在 "Slot 2 name" 之前,所以我写了一个小函数来比较字符串,同时考虑其中的数字。可能需要考虑一些边缘情况。

function strCmpWithNumbers( $a, $b) {
// 将字符串拆分成单词。
$a = explode(' ',$a);
$b = explode(' ',$b);
$loop = 0;
do {
// 获取每个项目的第一个单词
$ta = Utils::gvfa($a, $loop);
$tb = Utils::gvfa($b, $loop);

if (isset($ta)) {
if (isset($tb)) {
if (is_numeric($ta)) {
if ($ta != $tb) {
return $ta - $tb;
}
} else {
$val = strcasecmp($ta, $tb);
if ($val != 0) {
return $val;
}
}
} else {
return 1; // a 已设置但 b 未设置
}
} else {
return isset($b);
}
$loop +=1;
} while (true);
}
-5
匿名用户
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