|
|
 |
uksort (PHP 3 >= 3.0.4, PHP 4, PHP 5) uksort --
Sort an array by keys using a user-defined comparison function
Descriptionbool uksort ( array &array, callback cmp_function )
uksort() will sort the keys of an array using a
user-supplied comparison function. If the array you wish to sort
needs to be sorted by some non-trivial criteria, you should use
this function.
Function cmp_function should accept two
parameters which will be filled by pairs of array keys.
The comparison function must return an integer less than, equal
to, or greater than zero if the first argument is considered to
be respectively less than, equal to, or greater than the
second.
Returns TRUE on success or FALSE on failure.
Example 1. uksort() example |
<?php
function cmp($a, $b)
{
if ($a == $b) {
return 0;
}
return ($a > $b) ? -1 : 1;
}
$a = array(4 => "four", 3 => "three", 20 => "twenty", 10 => "ten");
uksort($a, "cmp");
while (list($key, $value) = each($a)) {
echo "$key: $value\n";
}
?>
|
The above example will output: 20: twenty
10: ten
4: four
3: three |
|
See also usort(), uasort(),
sort(), asort(),
arsort(), ksort(),
natsort(), and rsort().
User Contributed Notes
uksort
Jimomighty
19-Mar-2005 09:30
...
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 );
...
aleczapka at gmx dot net
22-Dec-2004 06:35
One remark regarding array_sorter class.
It won't work correctly with eg. dates from mysql like 20041206105350, cause you can't convert such number into integer. To fix it remove intval() from the code. If the variable is a number it will work without converting this to int anyways. Here is the fix.
<?php
....
if ($a == $b)
return 0;
if ($this->sasc)
return ($a > $b) ? 1 : -1;
else
return ($a > $b) ? -1 : 1;
...
?>
jg at delegation dot ca
17-Dec-2004 09:41
To sort dates with 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;
}
aleczapka at gmx dot net
06-Dec-2004 06:27
Here is a small and very fast object to handle sorting of multidimentional arrays by a key.
<?php
class array_sorter
{
var $skey = false;
var $sarray = false;
var $sasc = true;
function array_sorter(&$array, $key, $asc=true)
{
$this->sarray = $array;
$this->skey = $key;
$this->sasc = $asc;
}
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;
}
function _as_cmp($a, $b)
{
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;
}
}
}?>
Sample $input_array:
Array
(
[0] => Array
(
[id] => 961
[uid] => 29
[gid] => 12
[parent_id] => 147
[created] => 20041206105350
[modified] => 20041206110702
)
[1] => Array
(
[id] => 41
[uid] => 29
[gid] => 12
[parent_id] => 153
[created] => 20041025154009
[modified] => 20041206105532
)
[2] => Array
(
[id] => 703
[uid] => 29
[gid] => 12
[parent_id] => 419
[created] => 20041025154132
[modified] => 20041027150259
)
Example of usage:
<?php
function multi_sort(&$array, $key, $asc=true)
{
$sorter = new array_sorter($array, $key, $asc);
return $sorter->sortit();
}
$my_array = multi_sort($input_array, "parent_id", false);
?>
The result array will be:
Array
(
[0] => Array
(
[id] => 703
[uid] => 29
[gid] => 12
[parent_id] => 419
[created] => 20041025154132
[modified] => 20041027150259
)
[1] => Array
(
[id] => 41
[uid] => 29
[gid] => 12
[parent_id] => 153
[created] => 20041025154009
[modified] => 20041206105532
)
[2] => Array
(
[id] => 961
[uid] => 29
[gid] => 12
[parent_id] => 147
[created] => 20041206105350
[modified] => 20041206110702
)
fabriceb at gmx dot net
08-Jul-2004 08:26
(about sorting an array of objects by their properties in a class - inspired by webmaster at zeroweb dot org at usort function)
I'm using classes as an abstraction for querying records in a database and use arrays of objects to store records that have an 1 to n relationship. E.g. a class "family" has family members stored as an array of objects. Each of those objects prepresents a record in a database related to the family (by it's familyId).
To identify members, I'm using their memberId as the key of the array e.g. $family->members[$memberId].
To sort the family members AFTER fetching them with the database query, you can use the functions _objSort and sortMembers which will sort the "members" array by key using it's properties (for space reasons I didn't include the methods used to open the records):
<?php
class familyMember
{
var $memberId;
var $familyId;
var $firstName;
var $age;
var $hairColor;
}
class family
{
var $familyId;
var $name;
var $members = array(); 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 />";
}
?>
Note that this might not be the fastest thing on earth and it hasn't been tested very much yet but I hope it's useful for someone.
jOn
16-Mar-2004 07:57
a quick function to point uksort() at, for sorting by key, but ignoring "the" from any keys that start with it:
<?php
function comp($a,$b)
{
$a = preg_replace('|^the\b\W*|i','',$a);
$b = preg_replace('|^the\b\W*|i','',$b);
if ($a == $b) {
return 0;
}
return ($a > $b) ? 1 : -1;
}
?>
webmaster at kik-it at N0SP4M dot com
09-Feb-2004 12:03
The code below allows you to sort an array_A following array_B keys order, original keys and values remain associated.
<?
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);
?>
Will print :
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 )
The keys not listed in the $TheArrayOrder will appear at the end of your sorted array (only if Key Pos < 99999999 ;o)
guss at typo dot co dot il
07-Dec-2003 02:18
Regarding the recursive sorting function above:
Genrally speaking, any recursion can be reimplemented using simple iteration. in the specific case, using recursion to compare strings has a huge performance impact while a simple loop would suffice and be faster and more simple.
Recursion is only good if it simplifies your code or your understanding of the concept. the previous example does neither, especially as it does a lot of repetitive things in each iteration, such as asigning the character order constant, rebuilding it into an array and such
For example, the string comparison could be written as such :
function str_compare($a,$b) {
$order="aAáÁbBcCčČ..."; // longer normally & without that html entities
$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;
}
Which is much simpler and faster.
Note that the above function will break for characters that are not listed in $order. it should be failry trivial to fix it.
ignatius dot reilly at free dot fr
13-Nov-2003 12:59
To use a more complicated comparison function, one can use a callback to a method of an object instance.
For example the following will take an array $arr whose keys are the same as those of $reference, and reorder $arr so that the keys appear in the same order as in $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 ) ;
pachollini at stones dot com
03-Mar-2003 06:47
I tried to write my own function for sorting with special Czech characters, which php normally compares wrong way. The function is recoursive, it compares the first characters of the strings and when they're the same, the function calls itself with parameters without the first character. My php often crashed by calling this function. After some time if found the problem: it crashed after 10th recoursive call. I think it's a bug in php, and I've made this workaround:
function str_compare($a,$b,$level=0)
{
$maxlevel=9;
if($GLOBALS["STR_COMPARE"] && is_array($a))
{
$a=$a[$GLOBALS["STR_COMPARE"]];
$b=$b[$GLOBALS["STR_COMPARE"]];
}
$result=0;
if($a==$b) return 0;
elseif($a=="") return ($b=="") ? 0 : 1;
elseif ($b=="") return -1;
else
{
$order="aAáÁbBcCčČ..."; // longer normally & without that html entities
for($i=0;$i<strlen($order);$i++) $codes[]=ord($order[$i]);
$char_a=$a[0];$char_b=$b[0];
$pos_a=array_search(ord($a),$codes); $pos_b=array_search(ord($b),$codes);
//echo"$char_a - $pos_a<br>";
if($pos_a===false || $pos_b===false)
{
if($char_a==$char_b)
{
if ($level<=$maxlevel) $result=str_compare (substr($a,1),substr($b,1),$level+1);
else $a<$b ? $result=-1 : $result=1;
}
else ($char_a<$char_b) ? $result=-1 : $result=1;
}
else
{
if($pos_a==$pos_b)
{
if ($level<=$maxlevel) $result=str_compare(substr($a,1), substr($b,1),$level+1);
else $a<$b ? $result=-1 : $result=1;
}
else ($pos_a<$pos_b) ? $result=-1 : $result=1;
}
return $result;
}
}
kumar at chicagomodular (dot) com
29-Jan-2003 11:12
The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
--necessary info from http://www.php.net/manual/en/function.usort.php if you didn't see it already
| |