|
|
array_multisort (PHP 4, PHP 5) array_multisort -- Сортировать несколько массивов или многомерные массивы Описаниеbool array_multisort ( array ar1 [, mixed arg [, mixed ... [, array ...]]] )
Функция array_multisort() может быть использована для
сортировки сразу нескольких массивов или одного многомерного массива
в соответствии с одной или несколькими размерностями. Эта функция
сохраняет соответствие между ключами и соответствующими им значениями.
Входные массивы рассматриваются как столбцы таблицы, которую
нужно отсортировать по строкам - такой подход напоминает
поведение выражения SQL ORDER BY. Первый массив имеет
проиоритет в процессе сортировки.
Структура аргументов этой функции немного необычна,
но удобна. Первым аргументом должен быть массив. Последующие
аргументы могут быть как массивами, так и значениями,
определяющими порядок сортировки, приведенными в
нижеследующем списке.
Значения, определяющие порядок сортировки:
Sorting type flags:
SORT_REGULAR - сравнивать элементы обычным образом SORT_NUMERIC - сравнивать элементы, как если бы они были числами SORT_STRING - сравнивать элементы, как если бы они были строками
Недопустимым является указание двух флагов сортировки одинакового типа
после каждого массива. Флаги сортировки, переданные после аргумента
ar1, применяются только к этому аргументу -
перед тем, как функция начнет обрабатывать следующий массив, эти флаги
снова принимают значения по умолчаниюt SORT_ASC и SORT_REGULAR.
Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.
Пример 1. Сортировка нескольких массивов |
$ar1 = array ("10", 100, 100, "a");
$ar2 = array (1, 3, "2", 1);
array_multisort ($ar1, $ar2);
|
|
В вышеприведенном примере, после того, как будет осуществлена
сортировка, первый массив будет содержать 10, "a", 100, 100.
Второй - 1, 1, "2", 3. Элементы второго массива, соответствующие
идентичным элементам первого (100 и 100), также будут отсортированы.
Пример 2. Сортировка многомерного массива |
$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 (элементы отсортированы
как числа, в порядке убывания).
scott at bartoncomputer dot com
03-May-2007 10:18
I didn't see this noted anywhere, so I figured I'd put in a little comment regarding arrays located inside classes. For instance:
class abc
{
var $data;
}
The following code does not act as expected:
$clsVar =& new abc();
foreach ($clsVar->data as $key => $row)
{
$position[$key] = $key;
}
array_multisort($position, SORT_DESC, $clsVar->data);
While I realize this could much easily be acheived using ksort(), this is merely a much more simple example of this behaviour. The exerpt above comes from a much more complicated sort using multi-scripted arrays.
Anyway the only way I could find to get around the behaviour of multisort not sorting the referenced class-array was to make a copy of it as below:
$clsVar =& new abc();
$newData = $clsVar->data;
foreach ($newData as $key => $row)
{
$position[$key] = $key;
}
array_multisort($position, SORT_DESC, $newData);
Now newData will contain the sorted array as expected.
Hopefully this helps someone else!
10-Apr-2007 03:01
<?php
$strDeger = 'aaaa|bbbb|cccc';
$arrBol = explode('|',$strDeger);
array_multisort($arrBol, SORT_DESC);
for($i = 0; $i <= count($arrBol); $i++) {
echo $arrBol[$i].'<br />';
}
?>
vermon7
27-Feb-2007 01:23
When using array_multisort() on copies of arrays, it is changing all the copies, even if you modify the copy before using array_multisort().
I've avoided this bug by serializing a copy of array before calling array_multisort, and unserializg it after array_multisort() Look at the code:
<?php
$records_copy = serialize($records) ;
array_multisort ( $records[$sort_field] , $records[$sort2_field] ) ;
$records_copy = unserialize($records_copy) ;
?>
Jon L. -- intel352 [AT] gmail [DOT] com
26-Feb-2007 08:27
This is my solution for a dynamic multisort, using POST values. This doesn't account for a need to sort by multiple columns at once, but could be modified for that purpose.
<?php
$sort['direction'] = $_POST['sort_direction'] ? $_POST['sort_direction'] : 'SORT_ASC';
$sort['field'] = $_POST['sort_field'] ? $_POST['sort_field'] : 'value';
$array_to_sort = array();
$array_to_sort['TestCase1'] = array('name'=>'Test1','value'=>'218');
$array_to_sort['TestCase2'] = array('name'=>'Test2','value'=>'10');
$array_to_sort['TestCase3'] = array('name'=>'Test3','value'=>'64');
$sort_arr = array();
foreach($array_to_sort AS $uniqid => $row){
foreach($row AS $key=>$value){
$sort_arr[$key][$uniqid] = $value;
}
}
print '<b>Before sorting</b>: <br> <pre>';
print_r($array_to_sort);
print '</pre>';
if($sort['direction']){
array_multisort($sort_arr[$sort['field']], constant($sort['direction']), $array_to_sort);
}
print '<b>After sorting</b>: <br> <pre>';
print_r($array_to_sort);
print '</pre>';
?>
This example prints out:
Before sorting:
Array
(
[TestCase1] => Array
(
[name] => Test1
[value] => 218
)
[TestCase2] => Array
(
[name] => Test2
[value] => 10
)
[TestCase3] => Array
(
[name] => Test3
[value] => 64
)
)
After sorting:
Array
(
[TestCase2] => Array
(
[name] => Test2
[value] => 10
)
[TestCase3] => Array
(
[name] => Test3
[value] => 64
)
[TestCase1] => Array
(
[name] => Test1
[value] => 218
)
)
01-Dec-2006 06:58
casting the parameter arrays for array_multisort seem to make the sorting ineffective?
for example:-
<?
foreach((array)$report_files as $report_files_i)
{
$file_stat = stat($report_files_i);
$report_files_x[] = array(
'filename' => $report_files_i
,'basename' => basename($report_files_i)
,'ctime' => date("D, M j, Y",$file_stat['ctime'])
,'size' => $file_stat['size']
);
$basename_i[] = strtolower(basename($report_files_i)); // case insensitive
}
array_multisort($basename_i, SORT_ASC, $report_files_x);
?>
The above works but if you change the last time to :-
<?
array_multisort((array)$basename_i, SORT_ASC, (array)$report_files_x);
?>
...adding the (array) cast doesn't sort the main array ...
brettz9 throu gh yah
14-Sep-2006 12:04
Often, one may have a group of arrays which have parallel data that need to be kept associated with each other (e.g., the various attribute values of a group of elements might be stored in their own arrays). Using array_multisort as is, by specifying additional fields, it is possible, as in the documentation example cited below, that this association will be lost.
To take this example set of data from the documentation:
<?php
$ar1 = array("10", 100, 100, "a");
$ar2 = array(1, 3, "2", 1);
?>
The example goes on to sort it this way:
<?php
array_multisort($ar1, $ar2);
?>
In this case, although the "10" remains associated with the first '1' after being sorted, the "2" and '3' are reversed from their original order.
In order to sort by one field only (yet still have the other array(s) being correspondingly sorted), one can use array_keys (which makes an array out of the keys) to ensure that no further sub-sorting is performed. This works because array_keys is making an array for which no duplicates can exist (since keys will be unique), and thus, the subsequent fields will have no relevance as far as subsorting.
So, using the above data, we can perform this sort instead:
<?php
$ar3 = array_keys($ar1);
array_multisort($ar1, $ar3, $ar2);
?>
which, when $ar1 and $ar2 are dumped gives:
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]=> int(3)
[3]=> string(1) "2"
}
ricardo
04-Sep-2006 05:47
Hi,
Modded the function from KES,
goals:
- Object oriented
- string comparision using naturalordening
code:
<?
class HtmlTable{
var $sortorder;
var $rows;
//row adding stuf and constructor removed
function sort($sortorder){
if(is_array($sortorder)){
$this->sortorder=$sortorder;
usort($this->rows,array(&$this,'sort_compare'));
}
}
function sort_compare($a,$b){//sort function
$result=0;
foreach($this->sortorder as $key=>$value){
$result=strnatcmp($a[$key],$b[$key]);
if($result==0)continue;
if($value=='desc')$result=$result*-1;
break;
}
return $result;
}
}
?>
LPChip
28-Aug-2006 06:04
I was looking for a way to dynamically multisort my array.
By dynamically I mean that its not static what column will be sorted and if its ASC or DESC, and the ability to have more than one sorts.
This is the way a database would allow you to do.
The best way to dynamically do this, is by using eval.
The code below is partly what I used. (eg, I left out where the arrays were made and stuff, but the important part is here.)
<?
$orderby_arr = array("col1 ASC";"col2 DESC");
// prepare multisort using eval
$eval_sort = "array_multisort(";
if ($orderby !="") {
$orderby_arr_c = count($orderby_arr);
for ($orderby_walk=0; $orderby_walk < $orderby_arr_c; $orderby_walk++) {
$pos = strpos($orderby_arr[$orderby_walk], " ");
$orderby_col = substr($orderby_arr[$orderby_walk], 0, $pos);
$orderby_type = substr($orderby_arr[$orderby_walk], $pos+1);
$eval_sort .= "\$this->OrderBy[$orderby_col]" . ", SORT_$orderby_type,";
}
}
$eval_sort .= " \$this->Current_Query);";
// if there's an array, sort it.
if ($this->Current_Query_m != -1) eval($eval_sort);
?>
RQuadling at GMail dot com
07-Aug-2006 05:53
Extending KES's example (http://www.php.net/manual/en/function.array-multisort.php#68452) to look like array_multisort().
NOTE: Fully commented code is available at http://rquadling.php1h.com (sorry for the ads).
The syntax is the same as array_multisort().
You also have 3 additional parameters you can use:
AMC_SORT_STRING_CASELESS to sort the strings case insensitively.
AMC_LOSE_ASSOCIATION (the default behaviour) to lose the associations for the array.
AMC_KEEP_ASSOCIATION to keep the associations for the array.
Other than that, these function work together JUST like array_multisort but sorts using column(s) without the need to first extract the columns into individual arrays.
<?php
define ('AMC_SORT_STRING_CASELESS', SORT_STRING + 1);
define ('AMC_LOSE_ASSOCIATION', 1001);
define ('AMC_KEEP_ASSOCIATION', 1002);
define ('AMC_SORT_ORDER', 1003);
define ('AMC_SORT_TYPE', 1004);
function array_multisort_column(array &$a_data, $m_mixed1)
{
$a_Args = func_get_args();
$i_Args = func_num_args();
$GLOBALS['a_AMC_ordering'] = array();
$a_Columns = array_keys(reset($a_data));
$b_KeepAssociation = False;
for($i_Arg = 1 ; $i_Arg < $i_Args ; )
{
if (in_array($a_Args[$i_Arg], $a_Columns))
{
$s_Column = $a_Args[$i_Arg];
$GLOBALS['a_AMC_ordering'][$a_Args[$i_Arg]] = array
(
AMC_SORT_ORDER => SORT_ASC,
AMC_SORT_TYPE => SORT_REGULAR,
);
while
(
isset($a_Args[$i_Arg + 1]) &&
in_array
(
$a_Args[$i_Arg + 1],
array
(
AMC_KEEP_ASSOCIATION,
AMC_LOSE_ASSOCIATION,
AMC_SORT_STRING_CASELESS,
SORT_ASC,
SORT_DESC
SORT_NUMERIC,
SORT_REGULAR,
SORT_STRING,
),
True
)
)
{
if (in_array($a_Args[$i_Arg + 1], array(SORT_ASC, SORT_DESC), True))
{
$GLOBALS['a_AMC_ordering'][$s_Column][AMC_SORT_ORDER] = $a_Args[$i_Arg + 1];
}
elseif (in_array($a_Args[$i_Arg + 1], array(SORT_REGULAR, SORT_NUMERIC, SORT_STRING, AMC_SORT_STRING_CASELESS), True))
{
$GLOBALS['a_AMC_ordering'][$s_Column][AMC_SORT_TYPE] = $a_Args[$i_Arg + 1];
}
elseif (AMC_KEEP_ASSOCIATION == $a_Args[$i_Arg + 1])
{
$b_KeepAssociation = True;
}
++$i_Arg;
}
}
++$i_Arg;
}
$s_Sorter = ($b_KeepAssociation ? 'uasort' : 'usort');
$b_Result = $s_Sorter($a_data, 'array_multisort_column_cmp');
unset($GLOBALS['a_AMC_ordering']);
return $b_Result;
}
function array_multisort_column_cmp(array &$a_left, array &$a_right)
{
$i_Result = 0;
foreach($GLOBALS['a_AMC_ordering'] as $s_Column => $a_ColumnData)
{
switch ($a_ColumnData[AMC_SORT_TYPE])
{
case SORT_NUMERIC :
$i_ColumnCompareResult =
((intval($a_left[$s_Column]) == intval($a_right[$s_Column]))
?
0
:
((intval($a_left[$s_Column]) < intval($a_right[$s_Column]))
?
-1
:
1
)
);
break;
case SORT_STRING :
$i_ColumnCompareResult = strcmp((string)$a_left[$s_Column], (string)$a_right[$s_Column]);
break;
case AMC_SORT_STRING_CASELESS :
$i_ColumnCompareResult = strcasecmp((string)$a_left[$s_Column], (string)$a_right[$s_Column]);
break;
case SORT_REGULAR :
default :
$i_ColumnCompareResult =
(($a_left[$s_Column] == $a_right[$s_Column])
?
0
:
(($a_left[$s_Column] < $a_right[$s_Column])
?
-1
:
1
)
);
break;
}
if (0 == $i_ColumnCompareResult)
{
continue;
}
$i_Result = $i_ColumnCompareResult * (($a_ColumnData[AMC_SORT_ORDER] == SORT_DESC) ? -1 : 1);
break;
}
return $i_Result;
}
?>
KES http://kes.net.ua
27-Jul-2006 05:30
<?
//sort by second column then first one
$orderBy=array('0'=>'desc', 'first'=>'asc');
function KES_cmp($a, $b) {
global $orderBy;
$result= 0;
foreach( $orderBy as $key => $value ) {
if( $a[$key] == $b[$key] ) continue;
$result= ($a[$key] < $b[$key])? -1 : 1;
if( $value=='desc' ) $result= -$result;
break;
}
return $result;
}
$result= array();
$result[]= array( 'first'=>6, 2);
$result[]= array( 'first'=>3, 2);
$result[]= array( 'first'=>1, 3);
$result[]= array( 'first'=>1, 2);
$result[]= array( 'first'=>6, 1);
print "<b>Source</b>";
print_r($result);
usort($result, 'KES_cmp');
print "<b>Result</b>";
print_r($result);
?>
KES
27-Jul-2006 04:35
It is very handy to have function, which sort like this:
$arrayToSort[]= array(0 => ".", "type" => "dir");
$arrayToSort[]= array(0 => "qf", "type" => "file");
$arrayToSort[]= array(0 => "..", "type" => "dir");
$arrayToSort[]= array(0 => "text.txt", "type" => "file");
$arrayToSort[]= array(0 => "hello", "type" => "dir");
//first sort by the column 'type', then sort by the column '0'
$howToSort= array('type'=> 'asc', 0=> 'desc');
multisort($arrayToSort, $howToSort);
The result:
0 | type
----------------------------
. | dir
.. | dir
hello | dir
text.txt | file
qf | file
Cesar Sirvent
17-May-2006 09:43
There is a problem with array_multisort in languages other than English.
For special chars, as A with accent (
|
|