[编辑注:以下评论可能是错误的]
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'));
(关于按类中的属性对对象数组进行排序 - 受 webmaster at zeroweb dot org at usort 函数的启发)
我将类用作查询数据库记录的抽象,并使用对象数组来存储具有 1 对 n 关系的记录。例如,“家庭”类有一个成员数组存储家庭成员。这些对象中的每一个代表与家庭相关的数据库中的记录(通过其家庭 ID)。
为了识别成员,我使用他们的成员 ID 作为数组的键,例如 $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(); // 这将同时获取所有成员
// 按 3 个字段排序成员
$family->sortMembers(array("firstName" => "ASC", "age" => "DESC", "hairColor" => "ASC"));
// 输出所有家庭成员
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");
?>
如果你需要定期按等级排序(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
)
这对于许多人来说可能是显而易见的,但只是为了帮助那些试图在课堂上使用它的人。 在一个类中,你可以在 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 );
...
这是一个用于处理按键排序多维数组的小而快速的类。
<?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
)
以下代码允许您按照 array_B 键的顺序对 array_A 进行排序,原始键和值保持关联。
<?
//主函数
函数 SortArrayAKeysLikeArrayBKeys(&$TheArrayToSort){
uksort($TheArrayToSort,"SortArrayAKeysLikeArrayBKeys_cmp");
}
//自定义比较函数
函数 SortArrayAKeysLikeArrayBKeys_cmp($a,$b){
全局 $TheArrayOrder;
$PosA=KeyPosInArray($a,$TheArrayOrder);
$PosB=KeyPosInArray($b,$TheArrayOrder);
如果 ($PosA==$PosB){返回 0;}否则{返回 ($PosA > $PosB ? 1 : -1);}
}
//我的键在我的数组中的位置
函数 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)
要使用更复杂的比较函数,可以使用回调函数来调用对象实例的方法。
例如,以下代码将获取一个数组 $arr,其键与 $reference 的键相同,并重新排序 $arr,以便键的顺序与 $reference 中的顺序相同。
类 kcmp {
var $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 = 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 名称"
"插槽 2 名称"
"插槽 10 名称"
使用普通的字符串比较,"插槽 10 名称" 将出现在 "插槽 2 名称" 之前,因此我编写了一个小函数,它将在比较字符串时考虑数字。可能需要考虑一些边缘情况。
函数 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;
} 否则 {
}