 |
array_multisort (PHP 4, PHP 5) array_multisort -- 对多个数组或多维数组进行排序 说明bool array_multisort ( array ar1 [, mixed arg [, mixed ... [, array ...]]] )
如果成功则返回 TRUE,失败则返回 FALSE。
array_multisort()
可以用来一次对多个数组进行排序,或者根据某一维或多维对多维数组进行排序。
关联(string)键名保持不变,但数字键名会被重新索引。
输入数组被当成一个表的列并以行来排序――这类似于 SQL 的 ORDER BY
子句的功能。第一个数组是要排序的主要数组。数组中的行(值)比较为相同的话就按照下一个输入数组中相应值的大小来排序,依此类推。
本函数的参数结构有些不同寻常,但是非常灵活。第一个参数必须是一个数组。接下来的每个参数可以是数组或者是下面列出的排序标志。
排序顺序标志:
SORT_ASC - 按照上升顺序排序 SORT_DESC - 按照下降顺序排序
排序类型标志:
每个数组之后不能指定两个同类的排序标志。每个数组后指定的排序标志仅对该数组有效 - 在此之前为默认值
SORT_ASC 和 SORT_REGULAR。
例子 1. 对多个数组排序
<?php $ar1 = array("10", 100, 100, "a"); $ar2 = array(1, 3, "2", 1); array_multisort($ar1, $ar2);
var_dump($ar1); var_dump($ar2); ?>
|
本例中经过排序后,第一个数组将包含
"10","a",100,100。第二个数组将包含
1,1,"2",3。第二个数组中的项目顺序完全和第一个数组中相应的项目(100 和 100)顺序一致。
array(4) {
[0]=> string(2) "10"
[1]=> string(1) "a"
[2]=> int(100)
[3]=> int(100)
}
array(4) {
[0]=> int(1)
[1]=> int(1)
[2]=> string(1) "2"
[3]=> int(3)
} |
|
例子 2. 对多维数组排序
<?php $ar = array (array ("10", 100, 100, "a"), array (1, 3, "2", 1)); array_multisort ($ar[0], SORT_ASC, SORT_STRING, $ar[1], SORT_NUMERIC, SORT_DESC); ?>
|
|
本例中经过排序后,第一个数组将包含
10,100,100,"a"(作为字符串上升排序),第二个数组将包含
1,3,"2",1(作为数值下降排序)。
例子 3. Sorting multi-dimensional array
<?php $ar = array( array("10", 11, 100, 100, "a"), array( 1, 2, "2", 3, 1) ); array_multisort($ar[0], SORT_ASC, SORT_STRING, $ar[1], SORT_NUMERIC, SORT_DESC); var_dump($ar); ?>
|
本例中在排序后,第一个数组将变成
"10",100,100,11,"a"(被当作字符串以升序排列)。第二个数组将包含
1, 3, "2", 2, 1(被当作数字以降序排列)。
array(2) {
[0]=> array(5) {
[0]=> string(2) "10"
[1]=> int(100)
[2]=> int(100)
[3]=> int(11)
[4]=> string(1) "a"
}
[1]=> array(5) {
[0]=> int(1)
[1]=> int(3)
[2]=> string(1) "2"
[3]=> int(2)
[4]=> int(1)
}
} |
|
例子 4. 对数据库结果进行排序
本例中 data
数组中的每个单元表示一个表中的一行。这是典型的数据库记录的数据集合。
例子中的数据如下:
volume | edition
-------+--------
67 | 2
86 | 1
85 | 6
98 | 2
86 | 6
67 | 7 |
数据全都存放在名为 data
的数组中。这通常是通过循环从数据库取得的结果,例如
mysql_fetch_assoc()。
<?php $data[] = array('volume' => 67, 'edition' => 2); $data[] = array('volume' => 86, 'edition' => 1); $data[] = array('volume' => 85, 'edition' => 6); $data[] = array('volume' => 98, 'edition' => 2); $data[] = array('volume' => 86, 'edition' => 6); $data[] = array('volume' => 67, 'edition' => 7); ?>
|
本例中将把 volume 降序排列,把
edition 升序排列。
现在有了包含有行的数组,但是 array_multisort()
需要一个包含列的数组,因此用以下代码来取得列,然后排序。
<?php // 取得列的列表 foreach ($data as $key => $row) { $volume[$key] = $row['volume']; $edition[$key] = $row['edition']; }
// 将数据根据 volume 降序排列,根据 edition 升序排列 // 把 $data 作为最后一个参数,以通用键排序 array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data); ?>
|
数据集合现在排好序了,结果如下:
volume | edition
-------+--------
98 | 2
86 | 1
86 | 6
85 | 6
67 | 2
67 | 7 |
|
例子 5. 不区分大小写字母排序
SORT_STRING 和
SORT_REGULAR
都是区分大小写字母的,大写字母会排在小写字母之前。
要进行不区分大小写的排序,就要按照原数组的小写字母拷贝来排序。
<?php $array = array('Alpha', 'atomic', 'Beta', 'bank'); $array_lowercase = array_map('strtolower', $array);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $array);
print_r($array); ?>
|
上例将输出: Array
(
[0] => Alpha
[1] => atomic
[2] => bank
[3] => Beta
) |
|
【译者注】本函数相当有用,为有助于理解,请再看下面这个例子:
例子 6. 名次排列
<?php $grade = array("score" => array(70, 95, 70.0, 60, "70"), "name" => array("Zhang San", "Li Si", "Wang Wu", "Zhao Liu", "Liu Qi")); array_multisort($grade["score"], SORT_NUMERIC, SORT_DESC, // 将分数作为数值,由高到低排序 $grade["name"], SORT_STRING, SORT_ASC); // 将名字作为字符串,由小到大排序 var_dump($grade); ?>
|
上例将输出: array(2) {
["score"]=>
array(5) {
[0]=>
int(95)
[1]=>
string(2) "70"
[2]=>
float(70)
[3]=>
int(70)
[4]=>
int(60)
}
["name"]=>
array(5) {
[0]=>
string(5) "Li Si"
[1]=>
string(6) "Liu Qi"
[2]=>
string(7) "Wang Wu"
[3]=>
string(9) "Zhang San"
[4]=>
string(8) "Zhao Liu"
}
} |
本例中对包含成绩的数组 $grade
按照分数(score)由高到低进行排序,分数相同的人则按照名字(name)由小到大排序。排序后李四
95 分为第一名,赵六 60 分为第五名没有异议。张三、王五和刘七都是
70 分,他们的名次则由其姓名的字母顺序排列,Liu 在前,Wang 在后而
Zhang 在最后。为了区别,三个 70
分分别用了整数,浮点数和字符串来表示,可以在程序输出中清楚地看到它们排序的结果。
|
Cesar Sirvent
18-May-2006 12:43
There is a problem with array_multisort in languages other than English.
For special chars, as A with accent (), the sorting does not correspond to what might expect from a MySQL SELECT with ORDER BY.
For example
<?php
foreach ($students as $key => $row){
$surname[$key] = $row['surname'];
}
array_multisort($surname, SORT_ASC, $students);
?>
will sort the array in this way: ABADIA, ALVAREZ, BUUEL, ZUBIETA, LVARES
while a MySQL SELECT with ORDER BY nombre ASC will yield
ABADIA, LVARES, ALVEREZ, BUUEL, ZUBIETA
as A and are considered two different representations of the same letter.
scott - evolove - net - work it out
23-Mar-2006 11:51
A very simple way to sort an array of associative arrays by some value is to use usort.
I needed to sort an array of 20 data structures by their 'distance' value:
Array
(
[0] => Array
(
[blahblah] => blahblah
[distance] => 6
)
[1] => Array
(
you get the idea....
Here's the code:
--------------------
usort($results, "distributor_compare");
/**
* usort callback
*/
function distributor_compare($a, $b) {
$adist = intval($a['distance']);
$bdist = intval($b['distance']);
if ($adist == $bdist) {
return 0;
}
return ($adist < $bdist) ? -1 : 1;
}
--------------------
peter dot graham at tcat dot ac dot uk
16-Feb-2006 11:16
Many thanks to AlberT at SuperAlberT dot it for his useful and elegant function. I have made some small alterations so it doesnt use pass-by-reference as this throws up warnings in newer versions of php4.
<?php
function array_key_multi_sort($arr, $l , $f='strnatcasecmp')
{
usort($arr, create_function('$a, $b', "return $f(\$a['$l'], \$b['$l']);"));
return($arr);
}
?>
mail at theopensource dot com
01-Feb-2006 03:34
I wanted to share with you a function that I created to make the array_multisort process much easier for myself... There was some interesting things that I encountered and I will post that in the comments.
I created this function so that all I have to do is tell it what column I want to sort through in a one level deep multidimensional array. You can Try this code in your browser to view the results
ex/
<?php
//Here is an array example
$test[0]['name'] = "David";
$test[0]['age'] = 28;
$test[1]['name'] = "Dennis";
$test[1]['age'] = 23;
$test[2]['name'] = "Joseph";
$test[2]['age'] = 42;
//Here is the Function
function sortmddata($array, $by, $order, $type){
//$array: the array you want to sort
//$by: the associative array name that is one level deep
////example: name
//$order: ASC or DESC
//$type: num or str
$sortby = "sort$by"; //This sets up what you are sorting by
$firstval = current($array); //Pulls over the first array
$vals = array_keys($firstval); //Grabs the associate Arrays
foreach ($vals as $init){
$keyname = "sort$init";
$$keyname = array();
}
//This was strange because I had problems adding
//Multiple arrays into a variable variable
//I got it to work by initializing the variable variables as arrays
//Before I went any further
foreach ($array as $key => $row) {
foreach ($vals as $names){
$keyname = "sort$names";
$test = array();
$test[$key] = $row[$names];
$$keyname = array_merge($$keyname,$test);
}
}
//This will create dynamic mini arrays so that I can perform
//the array multisort with no problem
//Notice the temp array... I had to do that because I
//cannot assign additional array elements to a
//varaiable variable
if ($order == "DESC"){
if ($type == "num"){
array_multisort($$sortby,SORT_DESC, SORT_NUMERIC,$array);
} else {
array_multisort($$sortby,SORT_DESC, SORT_STRING,$array);
}
} else {
if ($type == "num"){
array_multisort($$sortby,SORT_ASC, SORT_NUMERIC,$array);
} else {
array_multisort($$sortby,SORT_ASC, SORT_STRING,$array);
}
}
//This just goed through and asks the additional arguments
//What they are doing and are doing variations of
//the multisort
return $array;
}
//Now to test it
$test = sortmddata($test,'age','ASC','num');
print_r ($test);
//This will return
//Array (
//[0] => Array ([name] => Dennis [age] => 23 )
//[1] => Array ( [name] => David [age] => 28 )
//[2] => Array ( [name] => Joseph [age] => 42 )
//)
?>
There you go... please let me know what you think if you like.
php a-t-the-r-a-t-e chir.ag
06-Jan-2006 06:10
Re: phu at kungphu, 19-Dec-2005 11:36
asort($test) will not let me specify which columns to sort ASC/DESC, NUMERIC/STRING etc.
I have data similar to what you specified. Now I want to sort $test by points DESC and name ASC. Here's my function that does it, based on suggestions on this page. It uses array_multisort (and hence acts just like it: preserving string-keys etc.)
<?php
function arrayColumnSort()
{
$n = func_num_args();
$ar = func_get_arg($n-1);
if(!is_array($ar))
return false;
for($i = 0; $i < $n-1; $i++)
$col[$i] = func_get_arg($i);
foreach($ar as $key => $val)
foreach($col as $kkey => $vval)
if(is_string($vval))
${"subar$kkey"}[$key] = $val[$vval];
$arv = array();
foreach($col as $key => $val)
$arv[] = (is_string($val) ? ${"subar$key"} : $val);
$arv[] = $ar;
call_user_func_array("array_multisort", $arv);
return $ar;
}
$test["pete"]['points']=1;
$test["pete"]['name']='Peter';
$test["mike"]['points']=5;
$test["mike"]['name']='Mike';
$test["zoo"]['points']=2;
$test["zoo"]['name']='John Zoo';
$test["ab"]['points']=2;
$test["ab"]['name']='John Ab';
$test1 = $test;
asort($test1);
$test2 = arrayColumnSort("points", SORT_DESC, SORT_NUMERIC, "name", SORT_ASC, SORT_STRING, $test);
print_r($test1); // asort
print_r($test2); // arrayColumnSort
?>
Output from asort:
Array
(
[pete] => Array
(
[points] => 1
[name] => Peter
)
[ab] => Array
(
[points] => 2
[name] => John Ab
)
[zoo] => Array
(
[points] => 2
[name] => John Zoo
)
[mike] => Array
(
[points] => 5
[name] => Mike
)
)
Output from arrayColumnSort:
Array
(
[mike] => Array
(
[points] => 5
[name] => Mike
)
[ab] => Array
(
[points] => 2
[name] => John Ab
)
[zoo] => Array
(
[points] => 2
[name] => John Zoo
)
[pete] => Array
(
[points] => 1
[name] => Peter
)
)
phu at kungphu
20-Dec-2005 03:36
Notepad's example using asort/arsort will -not- work unless 'points' is defined -before- 'name'.
Running the posted code sorts by 'name', which was not the point of the previous posts. Defining 'points' as 'apoints' also did not work; however, defining 'points' first yields correct sorting:
$test[0]['points']=1;
$test[0]['name']='Peter';
$test[1]['points']=5;
$test[1]['name']='Mike';
$test[2]['points']=2;
$test[2]['name']='John';
asort($test);
It appears asort uses the first defined element to sort a multidimensional array.
notepad at codewalkers dot com
10-Dec-2005 08:33
for you guys trying to sort scores on an associative multi-dimensional array, why are you creating your own functions?
<?php
$test[0]['name']='Peter';
$test[0]['points']=1;
$test[1]['name']='Mike';
$test[1]['points']=5;
$test[2]['name']='John';
$test[2]['points']=2;
asort($test);
// or even arsort();
?>
the above seems to work for me...
Shmee
30-Sep-2005 09:46
RWCs code works very well until you get a point value greater then ten. This is because the strcmp() function will return that 2 > 10 and 2 > 11 2 > 19 and so on. To compare number values over ten try a sort like this:
$test = multi_sort($test, $key = 'points');
function multi_sort($array, $akey)
{
function compare($a, $b)
{
global $key;
if ($a[$key]>$b[$key]){
$varcmp = "1";
return $varcmp;
}
elseif ($a[$key]<$b[$key]){
$varcmp = "-1";
return $varcmp;
}
elseif ($a[$key]==$b[$key]){
$varcmp = "0";
return $varcmp;
}
}
usort($array, "compare");
return $array;
}
RWC
26-Sep-2005 04:45
This is the simpler version of the function by AlberT.
A lot of times you have got an array like this:
$test[0]['name']='Peter';
$test[0]['points']=1;
$test[1]['name']='Mike';
$test[1]['points']=5;
$test[2]['name']='John';
$test[2]['points']=2;
You just want to sort on the index in the second dimension, ie. on points in the above example.
You can use the function below and call it like this:
$test = multi_sort($test, $key = 'points');
function multi_sort($array, $akey)
{
function compare($a, $b)
{
global $key;
return strcmp($a[$key], $b[$key]);
}
usort($array, "compare");
return $array;
}
Note: to be able to use $key in the compare function, it can not simply be passed as a parameter. It has to be declared global and set somewhere outside of compare().
AlberT at SuperAlberT dot it
18-Jul-2005 09:59
a nice piece of code to do an "array_key_multi_sort()" is the following:
<?php
/**
* orders a multidimentional array on the base of a label-key
*
* @param $arr, the array to be ordered
* @param $l the "label" identifing the field
* @param $f the ordering function to be used,
* strnatcasecmp() by default
* @return TRUE on success, FALSE on failure.
*/
function array_key_multi_sort(&$arr, $l , $f='strnatcasecmp') {
return usort($arr, create_function('$a, $b', "return $f(\$a['$l'], \$b['$l']);"));
}
?>
kencomer at kencomer dot com
13-Jun-2005 02:48
If your data is in an associative array that you would need to separate into columns such as those retrieved with your favorite flavor of _fetch_array() in order to be able to use multisort(), you should consider using uasort() or usort() as an alternative. Here is an example of how this could be beneficial:
(key is employee number which remains intact; rows are sorted by surname, firstname)
<?php
function namecmp( $row1,$row2 )
{
$first = strcmp($row1['surname'], $row2['surname']) ;
if ( $first )
return $first ;
else
return strcmp($row1['name'], $row2['name']) ;
}
$test = array( '11122202' => array('empno'=>11122202,'name'=>'geezer'
,'surname'=>'schmidt','age'=>96,'sex'=>'male')
,'11122204' => array('empno'=>11122204,'name'=>'coed'
,'surname'=>'beaujolais','age'=>18,'sex'=>'female')
,'11122206' => array('empno'=>11122206,'name'=>'immortal'
,'surname'=>'ramos','age'=>21,'sex'=>'male')
,'11122208' => array('empno'=>11122208,'name'=>'babyface'
,'surname'=>'brown','age'=>1,'sex'=>'male')
,'11122210' => array('empno'=>11122210,'name'=>'exjock'
,'surname'=>'gatti','age'=>48,'sex'=>'male')
,'11122212' => array('empno'=>11122212,'name'=>'jailbait'
,'surname'=>'muhammed','age'=>15,'sex'=>'female') )
;
echo "<pre>" ;
print_r( $test ) ;
uasort($test,'namecmp') ;
echo "----sorting----<br \>";
print_r( $test ) ;
echo "</pre>" ;
?>
Array
(
[11122202] => Array
(
[empno] => 11122202
[name] => geezer
[surname] => schmidt
[age] => 96
[sex] => male
)
[11122204] => Array
(
[empno] => 11122204
[name] => coed
[surname] => beaujolais
[age] => 18
[sex] => female
)
[11122206] => Array
(
[empno] => 11122206
[name] => immortal
[surname] => ramos
[age] => 21
[sex] => male
)
[11122208] => Array
(
[empno] => 11122208
[name] => babyface
[surname] => brown
[age] => 1
[sex] => male
)
[11122210] => Array
(
[empno] => 11122210
[name] => exjock
[surname] => gatti
[age] => 48
[sex] => male
)
[11122212] => Array
(
[empno] => 11122212
[name] => jailbait
[surname] => muhammed
[age] => 15
[sex] => female
)
)
----sorting----
Array
(
[11122204] => Array
(
[empno] => 11122204
[name] => coed
[surname] => beaujolais
[age] => 18
[sex] => female
)
[11122208] => Array
(
[empno] => 11122208
[name] => babyface
[surname] => brown
[age] => 1
[sex] => male
)
[11122210] => Array
(
[empno] => 11122210
[name] => exjock
[surname] => gatti
[age] => 48
[sex] => male
)
[11122212] => Array
(
[empno] => 11122212
[name] => jailbait
[surname] => muhammed
[age] => 15
[sex] => female
)
[11122206] => Array
(
[empno] => 11122206
[name] => immortal
[surname] => ramos
[age] => 21
[sex] => male
)
[11122202] => Array
(
[empno] => 11122202
[name] => geezer
[surname] => schmidt
[age] => 96
[sex] => male
)
)
Michael Oelze at M (myname) T GMXdotDE
26-Apr-2005 12:15
I try array_multisort at first and it seems to work well. But then I program a page with cached datas (the arrays were saved in a session). Suddenly the sort function doesn't seem to work. There was no error in my script, so I try the reference on the variables. Then he manage to sort the arrays again.
So it seems that if you save your Arrays in a session your arrays are global variables and then 'array_multisort' doesn't sort the arrays despite it gives back 'true'.
You must reference your variables and all work well:
session_start(); // restore variables (Arrays etc.)
.....
.....
array_multisort(&$Array1,&$Array2,&$Array3,...);
....
$_SESSION["Array1"]=$Array1;//
$_SESSION["Array2"]=$Array2;//Save Arrays in Session Data
$_SESSION["Array3"]=$Array3;//
......
Now you can store your Data Arrays in your Session and are able to sort them as you like...
stevec at NO-/ dot /-SPAM dot qiguang dot net
13-Apr-2005 11:19
Be careful when using array_multisort() on copies of arrays, as you might end up changing the original array. Given the following code:
<?php
$test1 = array(4,3,2,1);
$test2 = $test1;
$test3 = array('a', 'b', 'c', 'd');
array_multisort($test2, SORT_ASC, $test3);
echo 'test1:';
print_r($test1);
echo 'test2:';
print_r($test2);
echo 'test3:';
print_r($test3);
?>
You would expect:
test1:Array
(
[0] => 4
[1] => 3
[2] => 2
[3] => 1
)
test2:Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
test3:Array
(
[0] => d
[1] => c
[2] => b
[3] => a
)
However, if you run the code, you actually get:
test1:Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
test2:Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
)
test3:Array
(
[0] => d
[1] => c
[2] => b
[3] => a
)
Note that the original ($test1) ends up being sorted even though it was never called by array_multisort(). To work around this, insert a statement to modify the copy ($test2) before calling array_multisort() on it. The following code will produce the expected "correct" results:
<?php
$test1 = array(4,3,2,1);
$test2 = $test1;
$test3 = array('a', 'b', 'c', 'd');
$test2[0] = $test2[0]; // fix
array_multisort($test2, SORT_ASC, $test3);
echo 'test1:';
print_r($test1);
echo 'test2:';
print_r($test2);
echo 'test3:';
print_r($test3);
?>
This seems to be a resurrection of the closed bug #8130. Also, someone reported this behavior in bug #32031, but it was incorrectly labeled "bogus" in reference to bug #25359, which is a different issue.
joao at intrasystems dot com dot br
08-Apr-2005 03:27
Exemple of sorting multi-dimensional arrays by one of it's fields:
$result[0]['nome']='Joao';
$result[0]['order']=5;
$result[1]['nome']='Pedro';
$result[1]['order']=1;
$result[2]['nome']='Marcelo';
$result[2]['order']=3;
foreach($result as $res)
$sortAux[] = $res['order'];
array_multisort($sortAux, SORT_ASC, $result);
print_r($result);
produces:
Array
(
[0] => Array
(
[nome] => Pedro
[order] => 1
)
[1] => Array
(
[nome] => Marcelo
[order] => 3
)
[2] => Array
(
[nome] => Joao
[order] => 5
)
)
Toni
10-Nov-2004 07:30
An example to sort an array by 3 criteria:
$recordset is an array of results from a query to a database, that I sort using $matrix as auxiliary array. First numeric, Second and Third alphabetically.
<?php
for($idx=0;$idx<$toShow;$idx++){
$matrix[0][$id]=$recordset[$id][0];
$matrix[1][$id]=$recordset[$id][1];
$matrix[2][$id]=$recordset[$id][10];
}
array_multisort($matrix[0], SORT_DESC, SORT_NUMERIC,$matrix[1], SORT_STRING, SORT_ASC,$matrix[2], SORT_STRING, SORT_ASC);
?>
meddle at dzygn.com
05-Oct-2004 10:40
If you want to sort a multidomensional array by key name you cannot use array_multisort. ie: for an array named $archivos that prints like this:
Array
(
[0] => Array
(
[index] => 0
[name] => test
)
[1] => Array
(
[index] => 0
[name] => watertaxi.jpg
)
[2] => Array
(
[index] => 0
[name] => 2_0003.JPG
)
[3] => Array
(
[index] => 0
[name] => 24A_0025.JPG
)
[4] => Array
(
[index] => 1
[name] => _CIMG3501.JPG
)
)
If I wanted to order by "name" I'd use:
function comparar($a, $b) {
return strnatcasecmp($a["name"], $b["name"]);
}
usort($archivos, "comparar");
This function performs a case insensitive string comparison using a "natural order" algorithm (strnatcasecmp), resulting in:
Array
(
[0] => Array
(
[index] => 0
[name] => 2_0003.JPG
)
[1] => Array
(
[index] => 0
[name] => 24A_0025.JPG
)
[2] => Array
(
[index] => 0
[name] => test
)
[3] => Array
(
[index] => 0
[name] => watertaxi.jpg
)
[4] => Array
(
[index] => 1
[name] => _CIMG3501.JPG
)
)
kat dot n0spam at audiogalaxy dot com
24-Aug-2001 01:25
If you're having problems with array_multisort changing variables in global space when it is called inside a function and you're not passing in the function parameters by reference you can alleviate the problem by calling array_multisort with its parameters by reference.
array_multisort(&$a, SORT_DESC, &$b);
More details here in my bug report:
http://www.php.net/bugs.php?id=12936
|  |