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



PHP : Function Reference : Array Functions : natsort

natsort

Sort an array using a "natural order" algorithm (PHP 4, PHP 5)
bool natsort ( array &array )

This function implements a sort algorithm that orders alphanumeric strings in the way a human being would while maintaining key/value associations. This is described as a "natural ordering". An example of the difference between this algorithm and the regular computer string sorting algorithms (used in sort()) can be seen below:

Returns TRUE on success or FALSE on failure.

Example316.natsort() example

<?php
$array1
= $array2 = array("img12.png", "img10.png", "img2.png", "img1.png");

sort($array1);
echo
"Standard sorting\n";
print_r($array1);

natsort($array2);
echo
"\nNatural order sorting\n";
print_r($array2);
?>

The above example will output:

Standard sorting
Array
(
[0] => img1.png
[1] => img10.png
[2] => img12.png
[3] => img2.png
)

Natural order sorting
Array
(
[3] => img1.png
[2] => img2.png
[1] => img10.png
[0] => img12.png
)

For more information see: Martin Pool's Natural Order String Comparison page.


See also natcasesort(), strnatcmp(), and strnatcasecmp().

Related Examples ( Source code ) » natsort


Code Examples / Notes » natsort

xlab

Under limited testing, natsort() appears to work well for IP addresses. For my needs, it is far less code than the ip2long()/long2ip() conversion I was using before.

rasmus

To make a reverse function, you can simply:
function rnatsort(&$a){
natsort($a);
$a = array_reverse($a, true);
}


h3

This function can be very usefull, but in some cases, like if you want to sort a MySQL query result, it's important to keep in mind that MySQL as built'in sorting functions which are way faster than resorting the result using a complex php algorythm, especially with large arrays.
ex; 'SELECT * FROM `table` ORDER BY columnName ASC, columnName2 DESC'


lil

There's one little thing missing in this useful bit of code posted by mbirth at webwriters dot de:
<?php
function natsort2d(&$aryInput) {
 $aryTemp = $aryOut = array();
 foreach ($aryInput as $key=>$value) {
  reset($value);
  $aryTemp[$key]=current($value);
 }
 natsort($aryTemp);
 foreach ($aryTemp as $key=>$value) {
  $aryOut[$key] = $aryInput[$key];
// --------^^^^ add this if you want your keys preserved!
 }
 $aryInput = $aryOut;
}
?>


lacent

there is another rnatsort function lower on the page, but it didn't work in the context i needed it in.
reasoning for this:
sorting naturally via the keys of an array, but needing to reverse the order.
function rnatsort ( &$array = array() )
{
$keys = array_keys($array);
natsort($keys);
$total = count($keys) - 1;
$temp1 = array();
$temp2 = array();
// assigning original keys to an array with a backwards set of keys, to use in krsort();
foreach ( $keys as $key )
{
$temp1[$total] = $key;
--$total;
}

ksort($temp1);
// setting the new array, with the order from the krsort() and the values of original array.
foreach ( $temp1 as $key )
{
$temp2[$key] = $array[$key];
}
$array = $temp2;
}


12-mar-2006 03:44

The last comment should have been posted in doc about (r)sort( ). Indeed, and unfortunately, ORDER BY *does not* perform natural ordering. So, sometimes we *must* do a SQL request followed by natsort( ).

dslicer

Something that should probably be documented is the fact that both natsort and natcasesort maintain the key-value associations of the array. If you natsort a numerically indexed array, a for loop will not produce the sorted order; a foreach loop, however, will produce the sorted order, but the indices won't be in numeric order. If you want natsort and natcasesort to break the key-value associations, just use array_values on the sorted array, like so:
natsort($arr);
$arr = array_values($arr);


anonymous

Reverse Natsort:
 function rnatsort($a, $b) {
   return -1 * strnatcmp($a, $b);
 }
 usort($arr, "rnatsort");


justin

One of the things I've needed to do lately is apply natural sorting to a complex array, e.g.:
Array
(
[0] => Array
(
[ID] = 4
[name] = Fred
)

[1] => Array
(
[ID] = 6
[name] = Bob
)
)
where I want to sort the parent array by the child's name. I couldn't see a way of doing this using array_walk, so I've written a simple function to do it. Hopefully someone will find this useful:
/**
* @return Returns the array sorted as required
* @param $aryData Array containing data to sort
* @param $strIndex Name of column to use as an index
* @param $strSortBy Column to sort the array by
* @param $strSortType String containing either asc or desc [default to asc]
* @desc Naturally sorts an array using by the column $strSortBy
*/
function array_natsort($aryData, $strIndex, $strSortBy, $strSortType=false)
{
// if the parameters are invalid
if (!is_array($aryData) || !$strIndex || !$strSortBy)
// return the array
return $aryData;

// create our temporary arrays
$arySort = $aryResult = array();

// loop through the array
foreach ($aryData as $aryRow)
// set up the value in the array
$arySort[$aryRow[$strIndex]] = $aryRow[$strSortBy];

// apply the natural sort
natsort($arySort);
// if the sort type is descending
if ($strSortType=="desc")
// reverse the array
arsort($arySort);

// loop through the sorted and original data
foreach ($arySort as $arySortKey => $arySorted)
foreach ($aryData as $aryOriginal)
// if the key matches
if ($aryOriginal[$strIndex]==$arySortKey)
// add it to the output array
array_push($aryResult, $aryOriginal);
// return the return
return $aryResult;
}


awizemann

natsort() will not work correctly if you use underscores in file names (if your array is for sorting files).
Example:
$images = array('image_1.jpg','image_12.jpg');
Will not produce the same as:
$images = array('image1.jpg','image12.jpg');


natcasesort.too

I got caught out through naive use of this feature - attempting to sort a list of image filenames from a digital camera, where the filenames are leading zero padded (e.g. DSCF0120.jpg) , will not sort correctly.
Maybe the example could be modified to exhibit this behaviour
(e.g. set array to -img0120.jpg','IMG0.png', 'img0012.png', 'img10.png', 'img2.png', 'img1.png', 'IMG3.png)
If the example hadn't used images I would have coded it correctly first time around!


mroach

Here's an expansion of the natsort2d function that mbirth wrote. This one allows you to specify the key for sorting.
<?php
function natsort2d( &$arrIn, $index = null )
{

$arrTemp = array();
$arrOut = array();

foreach ( $arrIn as $key=>$value ) {

reset($value);
$arrTemp[$key] = is_null($index)
? current($value)
: $value[$index];
}

natsort($arrTemp);

foreach ( $arrTemp as $key=>$value ) {
$arrOut[$key] = $arrIn[$key];
}

$arrIn = $arrOut;

}
?>


@gmail bereikme

Here's a handy function to sort an array on 1 or more columns using natural sort:
<?php
// Example: $records = columnSort($records, array('name', 'asc', 'addres', 'desc', 'city', 'asc'));
$globalMultisortVar = array();
function columnSort($recs, $cols) {
global $globalMultisortVar;
$globalMultisortVar = $cols;
usort($recs, 'multiStrnatcmp');
return($recs);
}
function multiStrnatcmp($a, $b) {
global $globalMultisortVar;
$cols = $globalMultisortVar;
$i = 0;
$result = 0;
while ($result == 0 && $i < count($cols)) {
$result = ($cols[$i + 1] == 'desc' ? strnatcmp($b[$cols[$i]], $a[$cols[$i]]) : $result = strnatcmp($a[$cols[$i]], $b[$cols[$i]]));
$i+=2;
}
return $result;
}
?>
Greetings,
 - John


nissar_pa

Here is the program which will sort an array key in natural order and maintains key to data correlations
function natSortKey(&$arrIn)
{
  $key_array = array();
  $arrOut = array();
 
  foreach ( $arrIn as $key=>$value ) {
  $key_array[]=$key;
  }
 natsort( $key_array);
 foreach ( $key_array as $key=>$value ) {
 $arrOut[$value]=$arrIn[$value];
 }
 $arrIn=$arrOut;
}
Thanks,
Abdul Nissar


mbirth

For those who want to natsort a 2d-array on the first element of each sub-array, the following few lines should do the job.
<?php
function natsort2d(&$aryInput) {
 $aryTemp = $aryOut = array();
 foreach ($aryInput as $key=>$value) {
   reset($value);
   $aryTemp[$key]=current($value);
 }
 natsort($aryTemp);
 foreach ($aryTemp as $key=>$value) {
   $aryOut[] = $aryInput[$key];
 }
 $aryInput = $aryOut;
}
?>


phpnet

additional to the code posted by justin at redwiredesign dot com (which I found very usefull) here is a function that sorts complex arrays like this:
<?
$array['test0'] = array('main' =>  'a', 'sub' => 'a');
$array['test2'] = array('main' =>  'a', 'sub' => 'b');
$array['test3'] = array('main' =>  'b', 'sub' => 'c');
$array['test1'] = array('main' =>  'a', 'sub' => 'c');
$array['test4'] = array('main' =>  'b', 'sub' => 'a');
$array['test5'] = array('main' =>  'b', 'sub' => 'b');
?>
or
<?
$array[0] = array('main' =>  1, 'sub' => 1);
$array[2] = array('main' =>  1, 'sub' => 2);
$array[3] = array('main' =>  2, 'sub' => 3);
$array[1] = array('main' =>  1, 'sub' => 3);
$array[4] = array('main' =>  2, 'sub' => 1);
$array[5] = array('main' =>  2, 'sub' => 2);
?>
on one or more columns.
the code
<? $array = array_natsort_list($array,'main','sub'); ?>
will result in $array being sortet like this:
test0,test2,test1,test4,test5,test3
or
0,2,1,4,5,3.
you may even submit more values to the function as it uses a variable parameter list. the function starts sorting on the last and the goes on until the first sorting column is reached.
to me it was very usefull for sorting a menu having submenus and even sub-submenus.
i hope it might help you too.
here is the function:
<?
function array_natsort_list($array) {
// for all arguments without the first starting at end of list
for ($i=func_num_args();$i>1;$i--) {
// get column to sort by
$sort_by = func_get_arg($i-1);
// clear arrays
$new_array = array();
$temporary_array = array();
// walk through original array
       foreach($array as $original_key => $original_value) {
        // and save only values
           $temporary_array[] = $original_value[$sort_by];
       }
// sort array on values
       natsort($temporary_array);
       // delete double values
       $temporary_array = array_unique($temporary_array);
// walk through temporary array
       foreach($temporary_array as $temporary_value) {
// walk through original array
           foreach($array as $original_key => $original_value) {
            // and search for entries having the right value
               if($temporary_value == $original_value[$sort_by]) {
                // save in new array
                   $new_array[$original_key] = $original_value;
               }
           }
       }
// update original array
$array = $new_array;
}
return $array;
}
?>


flash

About the reverse natsort.. Maybe simpler to do :
function strrnatcmp ($a, $b) {
   return strnatcmp ($b, $a);
}


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