downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | conferences | my php.net

search for in the

next> <natcasesort
[edit] Last updated: Fri, 24 May 2013

view this page in

natsort

(PHP 4, PHP 5)

natsort 用“自然排序”算法对数组排序

说明

bool natsort ( array &$array )

本函数实现了一个和人们通常对字母数字字符串进行排序的方法一样的排序算法并保持原有键/值的关联,这被称为“自然排序”。本算法和通常的计算机字符串排序算法(用于 sort())的区别见下面示例。

参数

array

输入的 array。

返回值

成功时返回 TRUE, 或者在失败时返回 FALSE

更新日志

版本 说明
5.2.10 Zero padded numeric strings (e.g., '00005') now essentially ignore the 0 padding.

范例

Example #1 natsort() examples demonstrating basic usage

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

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

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

以上例程会输出:

Standard sorting
Array
(
    [3] => img1.png
    [1] => img10.png
    [0] => img12.png
    [2] => 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.

Example #2 natsort() examples demonstrating potential gotchas

<?php
echo "Negative numbers\n";
$negative = array('-5','3','-2','0','-1000','9','1');
print_r($negative);
natsort($negative);
print_r($negative);

echo 
"Zero padding\n";
$zeros = array('09''8''10''009''011''0'); 
print_r($zeros);
natsort($zeros);
print_r($zeros);

echo 
"Other characters interfering\n";
$images_oops = array('image_1.jpg','image_12.jpg''image_21.jpg''image_4.jpg');
print_r($images_oops);
natsort($images_oops);
print_r($images_oops);

echo 
"Sort by keys\n";
$smoothie = array('orange' => 1'apple' => 1'yogurt' => 4'banana' => 4);
print_r($smoothie);
uksort$smoothie'strnatcmp');
print_r($smoothie);
?>

以上例程会输出:

Negative numbers
Array
(
    [0] => -5
    [1] => 3
    [2] => -2
    [3] => 0
    [4] => -1000
    [5] => 9
    [6] => 1
)
Array
(
    [2] => -2
    [0] => -5
    [4] => -1000
    [3] => 0
    [6] => 1
    [1] => 3
    [5] => 9
)

Zero padding
Array
(
    [0] => 09
    [1] => 8
    [2] => 10
    [3] => 009
    [4] => 011
    [5] => 0
)
Array
(
    [5] => 0
    [1] => 8
    [3] => 009
    [0] => 09
    [2] => 10
    [4] => 011
)

Other characters interfering
Array
(
    [0] => image_1.jpg
    [1] => image_12.jpg
    [2] => image_21.jpg
    [3] => image_4.jpg
)
Array
(
    [0] => image_1.jpg
    [3] => image_4.jpg
    [1] => image_12.jpg
    [2] => image_21.jpg
)

Sort by keys
Array
(
    [orange] => 1
    [apple]  => 1
    [yogurt] => 4
    [banana] => 4
)
Array
(
    [apple]  => 1
    [banana] => 4
    [orange] => 1
    [yogurt] => 4
)

参见



next> <natcasesort
[edit] Last updated: Fri, 24 May 2013
 
add a note add a note User Contributed Notes natsort - [25 notes]
up
6
Johan GENNESSON (php at genjo dot fr)
2 years ago
Be careful of the new behaviour in 5.2.10 version.
See the following sample:

<?php

$array
= array('1 bis', '10 ter', '0 PHP', '0', '01', '01 Ver', '0 ', '1 ', '1');

natsort($array);
echo
'<pre>';
print_r($array);
echo
'</pre>';
?>

5.2.6-1 will output:
Array
(
    [3] => 0
    [6] => 0
    [2] => 0 OP
    [4] => 01
    [5] => 01 Ver
    [8] => 1
    [7] => 1
    [0] => 1 bis
    [1] => 10 ter
)

5.2.10 will output:
Array
(
    [6] => 0
    [3] => 0
    [8] => 1
    [4] => 01
    [7] => 1
    [5] => 01 Ver
    [0] => 1 bis
    [1] => 10 ter
    [2] => 0 OP
)

Greetings
up
2
flash at minet dot net
9 years ago
About the reverse natsort.. Maybe simpler to do :

function strrnatcmp ($a, $b) {
    return strnatcmp ($b, $a);
}
up
1
rasmus at flajm dot com
9 years ago
To make a reverse function, you can simply:

function rnatsort(&$a){
    natsort($a);
    $a = array_reverse($a, true);
}
up
1
justin at redwiredesign dot com
9 years ago
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;
}
up
1
@gmail bereikme
6 years ago
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
up
0
AJenbo
4 years ago
natsort might not act like you would expect with zero padding, heres a quick sample.

<?php
$array
= array('09', '8', '10', '009', '011');
natsort($array);
?>
/*
Array
(
    [3] => 009
    [4] => 011
    [0] => 09
    [1] => 8
    [2] => 10
)
*/
up
0
lacent at gmail dot com
6 years ago
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;
    }
up
0
natcasesort.too
7 years ago
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!
up
0
xlab AT adaptiveNOSPAMarts DOT net
9 years ago
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.
up
0
mbirth at webwriters dot de
9 years ago
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;
}

?>
up
0
anonymous at coward dot net
9 years ago
Reverse Natsort:

  function rnatsort($a, $b) {
    return -1 * strnatcmp($a, $b);
  }

  usort($arr, "rnatsort");
up
-1
jonathan_2097 at hotmail dot com
1 year ago
natsort by key
<?php
function knatsort($array)
{
    return
array_flip(natsort(array_flip($array));
}
?>
up
-1
phpnet at moritz-abraham dot de
8 years ago
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;
}
?>
up
0
Christoph
3 years ago
Note:

The natsort function will sort depending on the operating system, but not depending on either Linux or Windows-based systems

There's a difference when sorting an array which is generated from the filesystem:
Array(
    [0] => ./system/kernel/js/01_ui.core.js
    [1] => ./system/kernel/js/00_jquery-1.3.2.js
    [2] => ./system/kernel/js/02_my.desktop.js
)

natsort($array) will result in two different ways:

Case 1: (Debian)
Array(
    [1] => ./system/kernel/js/00_jquery-1.3.2.js
    [0] => ./system/kernel/js/01_ui.core.js
    [2] => ./system/kernel/js/02_my.desktop.js
)

Case 2: (Debian Kernel, but Ubuntu shadowed php-Version)
Array(
    [0] => ./system/kernel/js/01_ui.core.js
    [2] => ./system/kernel/js/02_my.desktop.js
    [1] => ./system/kernel/js/00_jquery-1.3.2.js
)

...so make sure you've named the files beginning with 01, then it works fine.
up
0
Anonymous
7 years ago
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( ).
up
0
h3
7 years ago
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'
up
0
lil at thedreamersmaze dot spam-me-not dot org
7 years ago
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;
}

?>
up
0
mroach at mroach dot com
7 years ago
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;
   
}

?>
up
-1
RuneImp at gmail dot com
1 year ago
A natural key sorting function that won't loose data. Using an array_flip technique might be faster but can loose data if the initial values are not all unique.

<?php
/**
 * keyNatSort does a natural sort via key on the supplied array.
 *
 * @param   $array      The array to natural sort via key.
 * @param   $saveMemory If true will delete values from the original array as it builds the sorted array.
 * @return  Sorted array on success. Boolean false if sort failed or null if the object was not an array.
 */
function keyNatSort($array, $saveMemory=false)
{
    if(
is_array($array))
    {
       
$keys = array_keys($array);
        if(
natsort($keys))
        {
           
$result = array();
            foreach(
$keys as $key)
            {
               
$result[$key] = $array[$key];
                if(
$saveMemory)
                    unset(
$array[$key]);
            }
               
        }
        else
           
$result = false;
    }
    else
       
$result = null;
   
    return
$result;
}
?>
up
-1
the_A at gmx dot at
3 years ago
Another approach to a natsord2d-function:
Imagine having an array like:
Array
(
    [subarray1] => Array
        (
            [1] => foo
            [2] => bar
        )
    [subarray2] => Array
        (
            [1] => 12
            [2] => 2     
        )
)
and you want to natsort it (=all the sub-arrays) by the values of sub-array2

<?php   
   
function natsort2d_custom (&$array, $sortby) {
       
natsort($array[$sortby]);    //First natsort the specified sub-array $sortby
       
$sorted_array = array();    //Create a temporary array
       
$sorted_array[$sortby] = $array[$sortby];     //Add the sorted sub-array to the temporary array with teh same key

       
foreach($array AS $key1=>$value1) {     //Walking through the rest of $array, ...
           
if($key1 != $sortby) {     //...leaving out [$sortby]
               
$sorted_array[$key1] = array();     //Create sub-array $key1

               
foreach ($array[$sortby] AS $key2=>$value2) {     //Walk trough $array[$sortby] (which is now already natsorted) key by key
                   
$sorted_array[$key1][$key2] = $array[$key1][$key2];
                   
// Put keys (and values) of array[$key1] in the same order as array[$sort] and stuff it into $sorted_array with the same key
               
}
            }
        }
       
$array = $sorted_array;
       
reset($array);
    }
?>
After sorting the array this way, it would be:
Array
(
    [subarray1] => Array
        (
           [2] => bar
           [1] => foo
           
        )
    [subarray2] => Array
        (
            [2] => 2           
            [1] => 12     
        )
)

This works, of course, with an unlimited amount of sub-arrays, provided none of the sub-arrays has a sub-array itself (non-recoursive)
up
-1
kirik-san at users.sourceforge.net
3 years ago
Just a reverse sorting function for "natural order" algorithm:
<?php
function natrsort(&$array)
{
   
natsort($array);
   
$array = array_reverse($array);
}

$arr = array("img12.png", "img2.png", "img1.png", "img10.png");
natrsort($arr);
print_r($arr);
?>
up
-1
ale152
4 years ago
Note: negatives number.
<?php
$a
= array(-5,-2,3,9);
natsort($a);
print_r($a);
?>
Will output:
Array ( [1] => -2 [0] => -5 [2] => 3 [3] => 9 )
up
-1
wyvern at greywyvern dot com
4 years ago
There's no need to include your own API code to natsort an associative array by key.  PHP's in-built functions (other than natsort) can do the job just fine:

<?php
  uksort
($myArray, "strnatcmp");
?>
up
-1
dslicer at maine dot rr dot com
9 years ago
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);
up
-2
awizemann at gmail dot com
5 years ago
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');

 
show source | credits | stats | sitemap | contact | advertising | mirror sites