文字

natsort

(PHP 4, PHP 5, PHP 7)

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
)

参见

  • natcasesort() - 用“自然排序”算法对数组进行不区分大小写字母的排序
  • 数组排序函数对比
  • strnatcmp() - 使用自然排序算法比较字符串
  • strnatcasecmp() - 使用“自然顺序”算法比较字符串(不区分大小写)

用户评论:

[#1] mvs dot php at gmail dot com [2015-05-20 10:12:24]

To naturally sort by array key, the uksort function can be used.

<?php

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

?>


Output:

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

See http://php.net/manual/en/function.uksort.php for more information about uksort and http://php.net/strnatcmp for usage of strnatcmp.

[#2] Johan GENNESSON (php at genjo dot fr) [2010-11-24 07:18:46]

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

[#3] Christoph [2009-11-25 22:45:58]

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.

[#4] ale152 [2009-03-16 14:00:40]

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 )

[#5] AJenbo [2009-01-15 13:33:02]

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

[#6] wyvern at greywyvern dot com [2008-12-17 10:53:28]

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

[#7] lacent at gmail dot com [2007-01-16 09:42:38]

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

[#8] @gmail bereikme [2006-09-01 08:06:39]

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 == && $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

[#9] [2006-03-12 07:44:08]

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

[#10] h3 [2006-02-22 08:59:56]

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'

[#11] lil at thedreamersmaze dot spam-me-not dot org [2006-01-31 08:38:15]

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

?>

[#12] natcasesort.too [2005-08-05 03:17:40]

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!

[#13] phpnet at moritz-abraham dot de [2004-09-02 14:09:04]

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:
<?php
$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
<?php
$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
<?php $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:
<?php
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;
}
?>

[#14] xlab AT adaptiveNOSPAMarts DOT net [2004-01-15 12:51:11]

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.

[#15] mbirth at webwriters dot de [2004-01-09 12:31:18]

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

?>

[#16] rasmus at flajm dot com [2003-12-14 21:30:47]

To make a reverse function, you can simply:

function rnatsort(&$a){
natsort($a);
$a = array_reverse($a, true);
}

[#17] justin at redwiredesign dot com [2003-08-22 10:10:49]

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:


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

[#18] flash at minet dot net [2003-08-12 10:27:42]

About the reverse natsort.. Maybe simpler to do :

function strrnatcmp ($a, $b) {
    return strnatcmp ($b, $a);
}

[#19] anonymous at coward dot net [2003-05-31 01:46:52]

Reverse Natsort:

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

  usort($arr, "rnatsort");

上一篇: 下一篇: