Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : Array Functions : uksort

uksort

Sort an array by keys using a user-defined comparison function (PHP 4, PHP 5)
bool uksort ( array &array, callback cmp_function )

Example 324. uksort() example

<?php
function cmp($a, $b)
{
   
$a = ereg_replace('^(a|an|the) ', '', $a);
   
$b = ereg_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";
}
?>

The above example will output:

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

Related Examples ( Source code ) » uksort


Code Examples / Notes » uksort

joelith

You can use this function to sort an array of days into order. We grabbed some data from a database which comes out as array('Monday'=>34, 'Sunday'=>45... etc but the day is not in order. So use this:
<?php
function cmp($a, $b){
$days = array('Tuesday'=>0, 'Wednesday'=>1, 'Thursday'=>2, 'Friday'=>3, 'Saturday'=>4, 'Sunday'=>5, 'Monday'=>6);
   // company logic dictates a week begins on a Tuesday.
if ($days[$a]<$days[$b]){
return -1;
}else{
return 1;
}
}
?>


ignatius dot reilly

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 ) ;


jg

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;
}


kumar

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


webmaster

The code below allows you to sort an array_A following array_B keys order, original keys and values remain associated.
<?
//main function
Function SortArrayAKeysLikeArrayBKeys(&$TheArrayToSort){
  uksort($TheArrayToSort,"SortArrayAKeysLikeArrayBKeys_cmp");
}
//the custom compare function
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);}
}
//where is my key in my array
Function KeyPosInArray($Key,$Array){
  $i=0;
  $Pos=99999999;
  if($Array){
     foreach($Array as $K => $V){
        $i++;
        if($K==$Key){
           $Pos=$i;
           break;
        }
     }
  }
  return $Pos;
}
//the array you want to sort
$AnyArrayToSort['age']='19';
$AnyArrayToSort['ville']='rennes';
$AnyArrayToSort['website']='kik-it.com';
$AnyArrayToSort['region']='bretagne';
$AnyArrayToSort['code_postal']='35200';
$AnyArrayToSort['Nom']='Fred';
//the array with the correct keys/values order
$TheArrayOrder['Nom']='Whatever';
$TheArrayOrder['age']='Anything';
$TheArrayOrder['region']='What u want';
$TheArrayOrder['ville']='Something';
$TheArrayOrder['code_postal']='Nothing';
//before sort
print_r($AnyArrayToSort);    
echo "
";
//we sort
SortArrayAKeysLikeArrayBKeys($AnyArrayToSort);
echo "
";
//after sort
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)


aleczapka

Since, so many people reused array_sorter class, I decided to put here some updated version with fixes.
<?php
//
// $Id: array_sorter.inc.php 82 2005-11-17 17:14:39Z aleczapka $
//
/**
* Handles multidimentional array sorting by a key (not recursive).
*
* @author Oliwier Ptak <aleczapka@gmail.com>
*/
class array_sorter
{
var $skey = false;
var $sarray = false;
var $sasc = true;
var $sas_object = false;
   /**
   * 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, $as_object=false) // {{{
{
$this->sarray = $array;
$this->skey = $key;
$this->sasc = $asc;
$this->sas_object = $as_object;
} // }}}
function debug()  // {{{
{
echo "skey: ".$this->skey."
";
echo "sasc: ".$this->sasc."
";
} // }}}
   /**
   * Sort method
   *
   * @access public
* @param boolean $remap if true reindex the array to reset indexes
   */
function sortit($remap=true)  // {{{
{
if (!is_array($this->sarray) || !array_key_exists($this->skey, @$this->sarray[0]))
return $this->sarray;
//$this->debug();
uksort($this->sarray, array($this, "_as_cmp"));
if ($remap)
{
$tmp = array();
while (list($id, $data) = each($this->sarray))
$tmp[] = $data;
return $tmp;
}
return $this->sarray;
} // }}}
/**
* 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))
{
//sort objects
if ($this->sas_object)
{
$obj_a = $this->sarray[$a];
$obj_b = $this->sarray[$b];
$str = "\$a = \$obj_a->$this->skey;";
$str .= "\$b = \$obj_b->$this->skey;";
eval($str);
}
else
{
$a = $this->sarray[$a][$this->skey];
$b = $this->sarray[$b][$this->skey];
}
}
//if string - use string comparision
if (!ctype_digit($a) && !ctype_digit($b) &&
!is_int($a) && !is_int($b))
{
if ($this->sasc)
return strcasecmp($a, $b);
else
return strcasecmp($b, $a);
}
else
{
if ($a == $b)
return 0;
if ($this->sasc)
return ($a > $b) ? 1 : -1;
else
return ($a > $b) ? -1 : 1;
}
}  // }}}
}//end of class
?>


guss

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&#269;&#268;..."; // 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.


aleczapka

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;
...
?>


fgallan

muti-array special sort funciton:
<?php
/// mycmp functions ///
function mycmp_asc($a, $b) {
   global $_CMP_FORMULA;
   static $_CMP_FORMULA_VA, $_CMP_FORMULA_VB;
   if (!$_CMP_FORMULA_VA) {
       $_CMP_FORMULA_VA = '$va = ' . str_replace('{}', '$a', $_CMP_FORMULA) . ';';
   }
   if (!$_CMP_FORMULA_VB) {
       $_CMP_FORMULA_VB = '$vb = ' . str_replace('{}', '$b', $_CMP_FORMULA) . ';';
   }
   eval($_CMP_FORMULA_VA);
   eval($_CMP_FORMULA_VB);
   if ($va == $vb) return 0;
   else return ($va < $vb ? -1 : 1);
}
function mycmp_desc($a, $b) {
   global $_CMP_FORMULA;
   static $_CMP_FORMULA_VA, $_CMP_FORMULA_VB;
   if (!$_CMP_FORMULA_VA) {
       $_CMP_FORMULA_VA = '$va = ' . str_replace('{}', '$a', $_CMP_FORMULA) . ';';
   }
   if (!$_CMP_FORMULA_VB) {
       $_CMP_FORMULA_VB = '$vb = ' . str_replace('{}', '$b', $_CMP_FORMULA) . ';';
   }
   eval($_CMP_FORMULA_VA);
   eval($_CMP_FORMULA_VB);
   if ($va == $vb) return 0;
   else return ($va > $vb ? -1 : 1);
}
/// run sort ///
$r = array(
   array(
       'name' => 'name1',
       'numbers' => array(1,3,5,7,9),
   ),
   array(
       'name' => 'name2',
       'numbers' => array(5,6,7,8,9),
   ),
   array(
       'name' => 'name3',
       'numbers' => array(1,2,3,4,5),
   ),
);
global $_CMP_FORMULA;
$_CMP_FORMULA = 'array_sum({}["numbers"])';
usort($r, "mycmp_desc");
echo '<pre>'; print_r($r); echo '</pre>';
?>
print:
Array
(
   [0] => Array
       (
           [name] => name2
           [numbers] => Array
               (
                   [0] => 5
                   [1] => 6
                   [2] => 7
                   [3] => 8
                   [4] => 9
               )
       )
   [1] => Array
       (
           [name] => name1
           [numbers] => Array
               (
                   [0] => 1
                   [1] => 3
                   [2] => 5
                   [3] => 7
                   [4] => 9
               )
       )
   [2] => Array
       (
           [name] => name3
           [numbers] => Array
               (
                   [0] => 1
                   [1] => 2
                   [2] => 3
                   [3] => 4
                   [4] => 5
               )
       )
)


commanace

I've written a small class that will sort arrays of objects by a certain attribute:
<?php
class t_object_sorter
{
protected $object_array;
protected $sort_by;

private function _comp($a,$b)
{
$key=$this->sort_by;
debug($this->object_array[$a],__FILE__,__LINE__);
if ($this->object_array[$a]->$key == $this->object_array[$b]->$key) return 0;
return ($this->object_array[$a]->$key < $this->object_array[$b]->$key) ? -1 : 1;
}

public function sort(&$object_array, $sort_by)
{
$this->object_array = $object_array;
$this->sort_by      = $sort_by;
uksort($object_array, array($this, "_comp"));
}
}
?>
It is used like that:
<?php
$sorter = new t_object_sorter;
$sorter->sort($menu->item, 'position');
?>
This call will sort all "item"-objects of the object "menu" by their attribute "position".
I hope this is helpfull.


pachollini

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&#269;&#268;..."; // 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
";
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;
}
}


aleczapka

Here is a small and very fast object to handle sorting of multidimentional arrays by a key.
<?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
?>
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();
}
//sort by parent_id in descending order
$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
       )


skippy

As silly as it may seem, you may sometimes need a comparison function which leaves the array in the same order. It's not as trivial as returning 0 (zero) all the time, since for some reason it doesn't actually leave the values alone.
Here's a simpler and faster version of the code presented by Ignatius Reilly in an earlier note, which can be used to infer original position based on the original array:
function cmp($a, $b) {
 if ($a == $b) return 0;
 global $target_array_here;
 static $keys;
 if (!$keys) $keys = array_keys($target_array_here);
 $x = array_search($a, $keys);
 $y = array_search($b, $keys);
 return ($x < $y ? -1 : 1);
}


toni soler

Added "sort_type" to the previous class (ascendent/descendent options)
<?php
class t_object_sorter
{
   var $object_array;
   var $sort_by;
   
   function _comp($a,$b)
   {
       $key=$this->sort_by;
       if ($this->object_array[$a]->$key == $this->object_array[$b]->$key) return 0;
       return ($this->object_array[$a]->$key < $this->object_array[$b]->$key) ? -1 : 1;
   }
   
   function _comp_desc($a,$b)
   {
       $key=$this->sort_by;
       if ($this->object_array[$a]->$key == $this->object_array[$b]->$key) return 0;
       return ($this->object_array[$a]->$key > $this->object_array[$b]->$key) ? -1 : 1;
   }
   
   function sort(&$object_array, $sort_by, $sort_type = "ASC")
   {
       $this->object_array = $object_array;
       $this->sort_by      = $sort_by;
       if ($sort_type == "DESC")
       {
           uksort($object_array, array($this, "_comp_desc"));
       }
       else
       {
           uksort($object_array, array($this, "_comp"));
       }
   }
}
?>


jon

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)
{
//remove "the" (case-insensitive), and any non-word
// characters from any string(s) that start with "the"
$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;
}
?>


jimomighty

...
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 );
...


fabriceb

(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(); // 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 />";
}
?>
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.


Change Language


Follow Navioo On Twitter
array_change_key_case
array_chunk
array_combine
array_count_values
array_diff_assoc
array_diff_key
array_diff_uassoc
array_diff_ukey
array_diff
array_fill_keys
array_fill
array_filter
array_flip
array_intersect_assoc
array_intersect_key
array_intersect_uassoc
array_intersect_ukey
array_intersect
array_key_exists
array_keys
array_map
array_merge_recursive
array_merge
array_multisort
array_pad
array_pop
array_product
array_push
array_rand
array_reduce
array_reverse
array_search
array_shift
array_slice
array_splice
array_sum
array_udiff_assoc
array_udiff_uassoc
array_udiff
array_uintersect_assoc
array_uintersect_uassoc
array_uintersect
array_unique
array_unshift
array_values
array_walk_recursive
array_walk
array
arsort
asort
compact
count
current
each
end
extract
in_array
key
krsort
ksort
list
natcasesort
natsort
next
pos
prev
range
reset
rsort
shuffle
sizeof
sort
uasort
uksort
usort
eXTReMe Tracker