PHPのお勉強!

PHP TOP

array_multisort

(PHP 4, PHP 5, PHP 7, PHP 8)

array_multisort複数または多次元の配列をソートする

説明

array_multisort(
    array &$array1,
    mixed $array1_sort_order = SORT_ASC,
    mixed $array1_sort_flags = SORT_REGULAR,
    mixed ...$rest
): bool

array_multisort() は、複数の配列を一度に、 または、多次元の配列をその次元の一つでソートする際に使用可能です。

連想配列のキー (string) は不変ですが、 数値添字は再度振り直されます。

注意:

比較結果が等しくなる二つの要素があった場合、それらの並び順は保持されます。PHP 8.0.0 より前のバージョンでは、ソートした配列におけるそれらの並び順は不定でした。

注意:

この関数をコールすると、配列の内部ポインタは最初の要素にリセットされます。

パラメータ

array1

ソートしたい配列。

array1_sort_order

先ほどの引数 array のソート順。 SORT_ASC はアイテムを昇順にソートし、 SORT_DESC はアイテムを降順にソートします。

この引数は、array1_sort_flags と入れ替えることもできるし、完全に省略することもできます。 省略した場合は SORT_ASC とみなします。

array1_sort_flags

先ほどの引数 array のソート方法。

これらのフラグが使えます。

  • SORT_REGULAR - アイテムを通常通り比較します (型を変更しません)。
  • SORT_NUMERIC - アイテムを数値として比較します。
  • SORT_STRING - アイテムを文字列として比較します。
  • SORT_LOCALE_STRING - 現在のロケールを考慮して、アイテムを文字列として比較します。利用するロケールは setlocale() で変更できます。
  • SORT_NATURAL - natsort() と同様の「自然順」で、アイテムを文字列として比較します。
  • SORT_FLAG_CASE - SORT_STRINGSORT_NATURAL と (ビット OR で) 組み合わせて、 大文字小文字を区別しない文字列のソートを指定します。

この引数は、array1_sort_order と入れ替えることもできるし、完全に省略することもできます。 省略した場合は SORT_REGULAR とみなします。

rest

追加の配列。オプションで並び順やフラグが続きます。 前の配列の比較結果が等しい要素に対応する要素群だけを比較します。 要するに、辞書的 (lexicographical) なソートを行うということです。

戻り値

成功した場合に true を、失敗した場合に false を返します。

例1 複数の配列をソートする

<?php
$ar1
= array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);

var_dump($ar1);
var_dump($ar2);
?>

この例では、ソートの後で、最初の配列は、0, 10, 100, 100 となります。 2番目の配列は、4, 1, 2, 3 を有します。最初の配列で等しい要素 (100 および 100) に対応している二番目の配列のエントリは、 同じ順にソートされます。

array(4) {
  [0]=> int(0)
  [1]=> int(10)
  [2]=> int(100)
  [3]=> int(100)
}
array(4) {
  [0]=> int(4)
  [1]=> int(1)
  [2]=> int(2)
  [3]=> int(3)
}

例2 多次元の配列をソートする

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

例3 データベースの結果をソートする

この例では、配列 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'];
}

// 上記のコードの代わりに array_column() を使用できます
$volume = array_column($data, 'volume');
$edition = array_column($data, '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

例4 大文字・小文字を区別しないソート

SORT_STRINGSORT_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
)

参考

add a note

User Contributed Notes 42 notes

up
221
jimpoz at jimpoz dot com
13 years ago
I came up with an easy way to sort database-style results. This does what example 3 does, except it takes care of creating those intermediate arrays for you before passing control on to array_multisort().

<?php
function array_orderby()
{
$args = func_get_args();
$data = array_shift($args);
foreach (
$args as $n => $field) {
if (
is_string($field)) {
$tmp = array();
foreach (
$data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return
array_pop($args);
}
?>

The sorted array is now in the return value of the function instead of being passed by reference.

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

// Pass the array, followed by the column names and sort flags
$sorted = array_orderby($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
?>
up
73
matt at bosc dot io
8 years ago
One-liner function to sort multidimensionnal array by key, thank's to array_column

<?php

array_multisort
(array_column($array, 'key'), SORT_DESC, $array);

?>
up
91
cagret at gmail dot com
15 years ago
A more inuitive way of sorting multidimensional arrays using array_msort() in just one line, you don't have to divide the original array into per-column-arrays:

<?php

$arr1
= array(
array(
'id'=>1,'name'=>'aA','cat'=>'cc'),
array(
'id'=>2,'name'=>'aa','cat'=>'dd'),
array(
'id'=>3,'name'=>'bb','cat'=>'cc'),
array(
'id'=>4,'name'=>'bb','cat'=>'dd')
);

$arr2 = array_msort($arr1, array('name'=>SORT_DESC, 'cat'=>SORT_ASC));

debug($arr1, $arr2);

arr1:
0:
id: 1 (int)
name: aA (string:2)
cat: cc (string:2)
1:
id: 2 (int)
name: aa (string:2)
cat: dd (string:2)
2:
id: 3 (int)
name: bb (string:2)
cat: cc (string:2)
3:
id: 4 (int)
name: bb (string:2)
cat: dd (string:2)
arr2:
2:
id: 3 (int)
name: bb (string:2)
cat: cc (string:2)
3:
id: 4 (int)
name: bb (string:2)
cat: dd (string:2)
0:
id: 1 (int)
name: aA (string:2)
cat: cc (string:2)
1:
id: 2 (int)
name: aa (string:2)
cat: dd (string:2)

function
array_msort($array, $cols)
{
$colarr = array();
foreach (
$cols as $col => $order) {
$colarr[$col] = array();
foreach (
$array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}
$eval = 'array_multisort(';
foreach (
$cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval(
$eval);
$ret = array();
foreach (
$colarr as $col => $arr) {
foreach (
$arr as $k => $v) {
$k = substr($k,1);
if (!isset(
$ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return
$ret;

}

?>
up
47
Robert C
10 years ago
Hi,

I would like to see the next code snippet to be added to http://nl3.php.net/array_multisort

Purpose: Sort a 2-dimensional array on some key(s)

Advantage of function:
- uses PHP's array_multisort function for sorting;
- it prepares the arrays (needed by array_multisort) for you;
- allows the sort criteria be passed as a separate array (It is possible to use sort order and flags.);
- easy to set/overwrite the way strings are sorted (case insensitive instead of case sensitive, which is PHP's default way of sorting);
- performs excellent

function MultiSort($data, $sortCriteria, $caseInSensitive = true)
{
if( !is_array($data) || !is_array($sortCriteria))
return false;
$args = array();
$i = 0;
foreach($sortCriteria as $sortColumn => $sortAttributes)
{
$colList = array();
foreach ($data as $key => $row)
{
$convertToLower = $caseInSensitive && (in_array(SORT_STRING, $sortAttributes) || in_array(SORT_REGULAR, $sortAttributes));
$rowData = $convertToLower ? strtolower($row[$sortColumn]) : $row[$sortColumn];
$colLists[$sortColumn][$key] = $rowData;
}
$args[] = &$colLists[$sortColumn];

foreach($sortAttributes as $sortAttribute)
{
$tmp[$i] = $sortAttribute;
$args[] = &$tmp[$i];
$i++;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return end($args);
}

Usage:

//Fill an array with random test data
define('MAX_ITEMS', 15);
define('MAX_VAL', 20);
for($i=0; $i < MAX_ITEMS; $i++)
$data[] = array('field1' => rand(1, MAX_VAL), 'field2' => rand(1, MAX_VAL), 'field3' => rand(1, MAX_VAL) );

//Set the sort criteria (add as many fields as you want)
$sortCriteria =
array('field1' => array(SORT_DESC, SORT_NUMERIC),
'field3' => array(SORT_DESC, SORT_NUMERIC)
);

//Call it like this:
$sortedData = MultiSort($data, $sortCriteria, true);
up
22
nick ([AT]) nickyost ([DOT]) com
13 years ago
USort function can be used to sort multidimensional arrays with almost no work whatsoever by using the individual values within the custom sort function.

This function passes the entire child element even if it is not a string. If it is an array, as would be the case in multidimensional arrays, it will pass the whole child array as one parameter.

Therefore, do something elegant like this:

<?php
// Sort the multidimensional array
usort($results, "custom_sort");
// Define the custom sort function
function custom_sort($a,$b) {
return
$a['some_sub_var']>$b['some_sub_var'];
}
?>

This does in 4 lines what other functions took 40 to 50 lines to do. This does not require you to create temporary arrays or anything. This is, for me, a highly preferred solution over this function.

Hope it helps!
up
7
frank at overdrunk dot net
15 years ago
I had a function to make a sort on a 2D array and I wanted to sort an array using a column that usualy contains numeric values but also strings.

Lets say we have this array :

Array (
[0] => Array ( "name" = "12000" ),
[1] => Array ( "name" = "113" ),
[2] => Array ( "name" = "test 01" ),
[3] => Array ( "name" = "15000 tests" ),
[4] => Array ( "name" = "45" ),
[5] => Array ( "name" = "350" ),
[6] => Array ( "name" = "725" ),
[7] => Array ( "name" = "hello" )
}

SORT_STRING whould have returned me this :

Array ( // Numeric values are not correctly sorted
[0] => Array ( "name" = "113" ),
[1] => Array ( "name" = "12000" ),
[2] => Array ( "name" = "15000 tests" ),
[3] => Array ( "name" = "350" ),
[4] => Array ( "name" = "45" ),
[5] => Array ( "name" = "725" ),
[6] => Array ( "name" = "hello" ),
[7] => Array ( "name" = "test 01" )
}

SORT_NUMERIC would have returned me this :

Array ( // String values are not sorted, just in the same order
[0] => Array ( "name" = "test 01" ),
[1] => Array ( "name" = "hello" ),
[2] => Array ( "name" = "45" ),
[3] => Array ( "name" = "113" ),
[4] => Array ( "name" = "350" ),
[5] => Array ( "name" = "725" ),
[6] => Array ( "name" = "12000" ),
[7] => Array ( "name" = "15000 tests" ),
}

So I've made this hybrid code which combines the best of both worlds by merging content sorted either way according to the first caracter of the string:

<?php
/**
* Sorts an array according to a specified column
* Params : array $table
* string $colname
* bool $numeric
**/
function sort_col($table, $colname) {
$tn = $ts = $temp_num = $temp_str = array();
foreach (
$table as $key => $row) {
if(
is_numeric(substr($row[$colname], 0, 1))) {
$tn[$key] = $row[$colname];
$temp_num[$key] = $row;
}
else {
$ts[$key] = $row[$colname];
$temp_str[$key] = $row;
}
}
unset(
$table);

array_multisort($tn, SORT_ASC, SORT_NUMERIC, $temp_num);
array_multisort($ts, SORT_ASC, SORT_STRING, $temp_str);
return
array_merge($temp_num, $temp_str);
}
?>

It would return something like this :

Array (
[2] => Array ( "name" = "45" ),
[3] => Array ( "name" = "113" ),
[4] => Array ( "name" = "350" ),
[5] => Array ( "name" = "725" ),
[6] => Array ( "name" = "12000" ),
[7] => Array ( "name" = "15000 tests" ),
[1] => Array ( "name" = "hello" ),
[0] => Array ( "name" = "test 01" ),
}
up
3
lingtalfi
3 years ago
For database like sorting, here is my 2 cents:

<?php
/**
* The RowsSortHelperTool class.
*/
class RowsSortHelperTool
{

/**
* Sorts the given array, based on the given sorts.
*
* The sorts argument is an array of field => direction,
*
* with:
*
* - field: string, the name of the property to sort the rows with
* - direction: string (asc|desc), the direction of the sort
*
*
* @param array $rows
* @param array $sorts
* @return array
*/
public static function sort(array &$rows, array $sorts)
{

$args = [];

foreach (
$sorts as $field => $direction) {
$col = array_column($rows, $field);
$args[] = $col;

if (
'asc' === $direction) {
$args[] = SORT_ASC;
} else {
$args[] = SORT_DESC;
}
}
$args[] = &$rows;
call_user_func_array("array_multisort", $args);
}
}

?>

Use it like this:

<?php
$data
[] = array('volume' => 67, 'edition' => 2, 'mine' => 5);
$data[] = array('volume' => 86, 'edition' => 1, 'mine' => 5);
$data[] = array('volume' => 85, 'edition' => 6, 'mine' => 5);
$data[] = array('volume' => 98, 'edition' => 2, 'mine' => 5);
$data[] = array('volume' => 86, 'edition' => 6, 'mine' => 4);
$data[] = array('volume' => 86, 'edition' => 6, 'mine' => 5);
$data[] = array('volume' => 67, 'edition' => 7, 'mine' => 5);

RowsSortHelperTool::sort($data, [
'volume' => 'desc',
'edition' => 'asc',
'mine' => 'desc',
]);

az($data);

?>

Will display something like this:

array(7) {
[0] => array(3) {
["volume"] => int(98)
["edition"] => int(2)
["mine"] => int(5)
}
[1] => array(3) {
["volume"] => int(86)
["edition"] => int(1)
["mine"] => int(5)
}
[2] => array(3) {
["volume"] => int(86)
["edition"] => int(6)
["mine"] => int(5)
}
[3] => array(3) {
["volume"] => int(86)
["edition"] => int(6)
["mine"] => int(4)
}
[4] => array(3) {
["volume"] => int(85)
["edition"] => int(6)
["mine"] => int(5)
}
[5] => array(3) {
["volume"] => int(67)
["edition"] => int(2)
["mine"] => int(5)
}
[6] => array(3) {
["volume"] => int(67)
["edition"] => int(7)
["mine"] => int(5)
}
}
up
16
zequez at gmail dot com
14 years ago
Easiest way I find out to sort an entire multidimensional array by one element of it:

<?php
$multiArray
= Array(
Array(
"id" => 1, "name" => "Defg"),
Array(
"id" => 2, "name" => "Abcd"),
Array(
"id" => 3, "name" => "Bcde"),
Array(
"id" => 4, "name" => "Cdef"));
$tmp = Array();
foreach(
$multiArray as &$ma)
$tmp[] = &$ma["name"];
array_multisort($tmp, $multiArray);
foreach(
$multiArray as &$ma)
echo
$ma["name"]."<br/>";

/* Outputs
Abcd
Bcde
Cdef
Defg
*/
?>

^-^
up
10
RWC
19 years ago
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().
up
1
faugeron dot loic at gmail dot com
8 years ago
Improving Example #3 (Sorting database results): using <?php array_column ?> (PHP >= 5.5) and <?php call_user_func_array ?> it becomes possible to build your sortings (sorting by one or many fields):

<?php

$data
= [
[
'id' => '168ac7f8-c918-4e99-90ee-5d7590fe61ce',
'name' => 'Arthur Dent',
],
[
'id' => 'e3ad45ee-7cae-4cca-bd7b-2eb6b57b6457',
'name' => 'Ford Prefect',
],
[
'id' => 'a426aef2-19e2-412a-8339-5458cf6ae416',
'name' => 'Trillian Astra',
],
];
$sortings = [
[
'field' => 'id',
'direction' => SORT_DESC,
],
];

$args = [];
$key = 0;
foreach (
$sortings as $sorting) {
$args[$key] = array_column($data, $sorting['field']);
$args[$key + 1] = $sorting['direction'];
$key += 2;
}
$args[] = $data;
call_user_func_array('array_multisort', $args);

// $data is now sorted by ID in descending order.
?>
up
1
nospam at nospam dot com
8 years ago
Super easy and simple way to sort a keyed multiarray while maintaining all associative keys, including numeric!

Preserves the original multiarray order if the sorting values are equal.

<?php
// sorts multiarray by a subarray value while preserving all keys, also preserves original order when the sorting values match
function maSort($ma = '', $sortkey = '', $sortorder = 1) { // sortorder: 1=asc, 2=desc
if ($ma && is_array($ma) && $sortkey) { // confirm inputs
foreach ($ma as $k=>$a) $temp["$a[$sortkey]"][$k] = $a; // temp ma with sort value, quotes convert key to string in case numeric float
if ($sortorder == 2) { // descending
krsort($temp);
} else {
// ascending
ksort($temp);
}
$newma = array(); // blank output multiarray to add to
foreach ($temp as $sma) $newma += $sma; // add sorted arrays to output array
unset($ma, $sma, $temp); // release memory
return $newma;
}
}
?>
up
3
brettz9 throu gh yah
18 years ago
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"
}
up
2
m dot michalczyk at gmail dot com
15 years ago
Here is useful example based on za at byza dot it solution to sort multidimensional objects by any dimension.
za at byza dot it
<?php
/* Example structure */
class person{
function
__construct($firstName, $lastName, $title, $position){
$this->firstName = $firstName;
$this->lastName = $lastName;
$this->title = new title($title);
$this->position = new position($position);
}
}
class
title{
function
__construct($name){
$this->name = $name;
}

}
class
position{
function
__construct($name){
$this->name = $name;
}

}

$array[] = new person('Piotr', 'Sobiepanek', 'b', 'b');
$array[] = new person('Piotr', 'Kowalski', 'b', 'a');
$array[] = new person('Piotr', 'Michalski', 'a', 'a');
$array[] = new person('Jozef', 'Smietana', 'a', 'b');
$array[] = new person('Jozef', 'Cmietana', 'a', 'b');
$array[] = new person('Marcin', 'Kondraciuk', 'c', 'b');
$array[] = new person('Maksym', 'Kondraciuk', 'c', 'd');
$array[] = new person('Ambrozy', 'Kondraciuk', 'c', 'd');
$array[] = new person('Alojzy', 'Kondraciuk', 'c', 'd');

array_sort($array, 'title->name', 'position->name', 'lastName');
print_r($array);

/* Source */

function hod(&$base, $path){
$keys = explode("->", $path);
$keys[0] = str_replace('$', '', $keys[0]);
$expression = '$ret = ';
$expression.= '$';
foreach (
$keys as $key){
if (++
$licz == 1){
$expression.= 'base->';
} else {
$expression.= $key.'->';
}
}
$expression = substr($expression, 0, -2);
$expression.= ';';
eval(
$expression);
return
$ret;
}

function
array_sort_func($a,$b=NULL) {
static
$keys;
if(
$b===NULL) return $keys=$a;
foreach(
$keys as $k) {
if(
$k[0]=='!') {
$k=substr($k,1);
if(
hod($a, '$a->'.$k)!==hod($b, '$b->'.$k)) {
return
strcmp(hod($b, '$b->'.$k),hod($a, '$a->'.$k));
}
}
else if(
hod($a, '$a->'.$k)!==hod($b, '$b->'.$k)) {
return
strcmp(hod($a, '$a->'.$k),hod($b, '$b->'.$k));
}
}
return
0;
}

function
array_sort(&$array) {
if(!
$array) return $keys;
$keys=func_get_args();
array_shift($keys);
array_sort_func($keys);
usort($array,"array_sort_func");
}
?>
up
3
Magento-User
11 years ago
When sorting an array of (complex) objects, this function can give you a "Fatal error: Nesting level too deep" since it directly compares elements in later arrays if the elements in earlier ones compare equal. This can be worked around with the Flag-Parameter:
<?php
$sortKeys
= array_map($extractKey, $lotsOfComplexObjects);
array_multisort($sortKeys, $lotsOfComplexObjects, SORT_ASC, SORT_NUMERIC);
?>
I'm replacing an 'uasort()'-call which is significantly slower since it leads to a lot of calls to the comparison-function but most of the objects involved are recursive.

If this 'trick' gives a wrong order, you need a better key.
up
1
Patrick Adrichem
11 years ago
If you do not have PHP 5.4 installed yet and you cannot use SORT_NATURAL. This function sorts arrays natural multi-dimensional based on key value

this function can be used for arrays as

array ( name => array( key => value ) )
and

array( name => value ).

arrays as array( name => array( key => value), name => value) are not supported.

<?php
static function natcasesortRecursive(&$aArray)
{
$bHasArrays = false;
foreach (
$aArray as $sKey => &$mValue)
{
if (
true === is_array($mValue))
{
self::natcasesortRecursive($mValue);
$bHasArrays = true;
}
}
if (
true === $bHasArrays)
{
uksort($aArray, 'strnatcasecmp');
}
else
{
natcasesort($aArray);
}
}
?>
up
1
jcharpentier at darkmira dot fr
10 years ago
There is a lack of precision for the second example :

Example #2 Sorting multi-dimensional array

The explanation is :
"In this example, [...] The second will contain 1, 3, "2", 2, 1 (sorted as numbers, in descending order). "
This could be misunderstood cause a sort as numbers in descending order will be 1, 1, "2", 2, 3.

My proposal is as follows (in a best english should be great ^^) :
"In this example, [...] The second will contain 1, 3, "2", 2, 1 (sorted as well as first one, except for values 3 and "2" sorted as numbers, in descending order). Because they are corresponding to the identical entries in the first array (100 and 100) which couldn't be sorted at first time."
up
1
alexander dot v at zend dot com
14 years ago
array_multisort works normally in php 5.3, but it forces arguments to be references.

It doesn't make differences for common array_multisort() usage, but makes "problems" for sorting variable number of arrays where call_user_func_array() function is involved.

So all sorting arrays have to be collected into new one as a references to array variables:

<?php
$sortArgs
= array();

for (...) {
...
$sortArgs[] = &$valuesArray;
...
}

call_user_func_array('array_multisort', $sortArgs);
?>

This (requiring arguments to be a reference) is not actually a problem since source array will not be sorted otherwise.

Important note!
Don't forget to destroy $valuesArray variable if you use it over each array_multisort() argument processing iteration.
If you don't do it, all array_multisort() arguments will contain the same array:

<?php
for (...) {
...
$sortArgs[] = &$valuesArray;
unset(
$valuesArray);
...
}
?>

And the last important thing :)
Collect sorting arrays somewhere. PHP 5.3 will transfer reference into value (when $valuesArray is destroyed) and you will get "Parameter 1 to array_multisort() expected to be a reference, value given" warning again otherwise.

Final code should look like this:

<?php
$sortArgs
= array();
$sortFieldValues = array();

for (...) {
...
$sortFieldValues[] = &$valuesArray;
$sortArgs[] = &$valuesArray;
unset(
$valuesArray);
...
}

call_user_func_array('array_multisort', $sortArgs);
?>
up
1
mech.cx
15 years ago
I was (as near everyone here :-) looking to sort 2-dimensional arrays by certain fields in the associative sub-arrays.
What I didn't like about the documentation examples is that you need to loop through the input array to create sub arrays first, then use those in the function call.

"php a-t-the-r-a-t-e chir.ag" (http://www.php.net/manual/en/function.array-multisort.php#60401) wrote a quite cunning wrapper function, I rewrote it slightly, changing variable names and adding comments (for my sanity :-) mostly.
One snag I found: the input array is passed to array_multisort as last argument, but the changed array is not the one that is returned. Passing it by reference fixed that. This seems to be caused by the whole thing sitting inside the call_user_func_array, as shown below.

<?php

$points
= array(1, 5, 2, 2);
$names = array('peter', 'mike', 'john Zoo', 'john Ab');

$source = array (
array (
'points' => 1, 'name' => 'Peter'),
array (
'points' => 5, 'name' => 'Mike'),
array (
'points' => 2, 'name' => 'John Zoo'),
array (
'points' => 2, 'name' => 'John Ab')
);

call_user_func_array('array_multisort', array($points, SORT_DESC, SORT_NUMERIC, $names, SORT_ASC, SORT_STRING, $source)); // doesn't work
print_r($source);
call_user_func_array('array_multisort', array($points, SORT_DESC, SORT_NUMERIC, $names, SORT_ASC, SORT_STRING, &$source)); // works!
print_r($source);

// Call like arrayColumnSort('points', SORT_DESC, SORT_NUMERIC, 'name', SORT_ASC, SORT_STRING, $source);

// Slightly adapted from http://www.php.net/manual/en/function.array-multisort.php#60401

// arrayColumnSort(string $field, [options, ], string $field2, [options, ], .... , $array) /

//____________________
// arrayColumnSort() /
function arrayColumnSort() {
$args = func_get_args();
$array = array_pop($args);
if (!
is_array($array)) return false;
// Here we'll sift out the values from the columns we want to sort on, and put them in numbered 'subar' ("sub-array") arrays.
// (So when sorting by two fields with two modifiers (sort options) each, this will create $subar0 and $subar3)
foreach($array as $key => $row) // loop through source array
foreach($args as $akey => $val) // loop through args (fields and modifiers)
if(is_string($val)) // if the arg's a field, add its value from the source array to a sub-array
${"subar$akey"}[$key] = $row[$val];
// $multisort_args contains the arguments that would (/will) go into array_multisort(): sub-arrays, modifiers and the source array
$multisort_args = array();
foreach(
$args as $key => $val)
$multisort_args[] = (is_string($val) ? ${"subar$key"} : $val);
$multisort_args[] = &$array; // finally add the source array, by reference
call_user_func_array("array_multisort", $multisort_args);
return
$array;
}

?>
up
0
Anonymous
2 months ago