PHP Doku:: Sortiert mehrere oder multidimensionale Arrays - function.array-multisort.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzVariablen- und typbezogene ErweiterungenArraysArray Funktionenarray_multisort

Ein Service von Reinhard Neidl - Webprogrammierung.

Array Funktionen

<<array_merge

array_pad>>

array_multisort

(PHP 4, PHP 5)

array_multisortSortiert mehrere oder multidimensionale Arrays

Beschreibung

bool array_multisort ( array &$arr [, mixed $arg = SORT_ASC [, mixed $arg = SORT_REGULAR [, mixed $... ]]] )

array_multisort() wird zum Sortieren von entweder mehreren Arrays auf einmal, oder eines multidimensionalen Arrays nach einer oder mehreren Dimensionen benutzt.

Assoziative (string) Schlüssel werden beibehalten, während numerische Schlüssel neu indexiert werden.

Parameter-Liste

arr

Ein zu sortierendes array.

arg

Optional ein weiteres array, oder Sortieroptionen für das vorherige array-Argument: SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING.

...

Weitere Parameter (arg).

Rückgabewerte

Gibt bei Erfolg TRUE zurück. Im Fehlerfall wird FALSE zurückgegeben.

Beispiele

Beispiel #1 Sortieren mehrerer Arrays

<?php
$ar1 
= array(101001000);
$ar2 = array(1324);
array_multisort($ar1$ar2);

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

In diesem Beispiel enthält das erste Array nach dem Sortieren 0, 10, 100, 100. Das zweite Array wird 4, 1, 2, 3 enthalten. Die Einträge des zweiten Arrays, welche den identischen Einträgen des ersten Arrays entsprechen (100 und 100), wurden ebenfalls sortiert.

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

Beispiel #2 Sortieren eines mehrdimensionalen Arrays

<?php
$ar 
= array(
       array(
"10"11100100"a"),
       array(   
1,  2"2",   3,   1)
      );
array_multisort($ar[0], SORT_ASCSORT_STRING,
                
$ar[1], SORT_NUMERICSORT_DESC);
var_dump($ar);
?>

In diesem Beispiel wird sich das erste Array nach der Sortierung in "10", 100, 100, 11, "a" ändern (es wurde als Strings in aufsteigender Reihenfolge sortiert). Das zweite wird 1, 3, "2", 2, 1 enthalten (sortiert als Zahlen in absteigender Reihe).

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

Beispiel #3 Datenbankdaten sortieren

In diesem Beispiel repräsentiert jedes Element des Arrays data eine Zeile einer Tabelle. Dieser Typ von Datensätzen ist typisch für Datenbankinhalte.

Beispieldaten:

Band   | Auflage
-------+--------
    67 |       2
    86 |       1
    85 |       6
    98 |       2
    86 |       6
    67 |       7

Die Daten als data genanntes Array. Dieses würde man üblicherweise erhalten, indem man zum Beispiel mit mysql_fetch_assoc() eine Schleife baut.

<?php
$data
[] = array('Band' => 67'Auflage' => 2);
$data[] = array('Band' => 86'Auflage' => 1);
$data[] = array('Band' => 85'Auflage' => 6);
$data[] = array('Band' => 98'Auflage' => 2);
$data[] = array('Band' => 86'Auflage' => 6);
$data[] = array('Band' => 67'Auflage' => 7);
?>

In diesem Beispiel werden wir nach Band absteigend sortieren und nach Auflage aufsteigend.

Wir haben ein Array von Zeilen, aber array_multisort() benötigt ein Array von Spalten, daher benutzen wir den Code unten, um die Spalten zu bekommen und dann die Sortierung durchzuführen.

<?php
// Hole eine Liste von Spalten
foreach ($data as $key => $row) {
    
$band[$key]    = $row['Band'];
    
$auflage[$key] = $row['Auflage'];
}

// Die Daten mit 'Band' absteigend, die mit 'Auflage' aufsteigend sortieren.
// Geben Sie $data als letzten Parameter an, um nach dem gemeinsamen
// Schlüssel zu sortieren.
array_multisort($bandSORT_DESC$auflageSORT_ASC$data);
?>

Der Datensatz ist jetzt sortiert und wird wie folgt aussehen:

Band | Auflage
-----+--------
  98 |       2
  86 |       1
  86 |       6
  85 |       6
  67 |       2
  67 |       7

Beispiel #4 Groß-/Kleinschreibung nicht-beachtende Sortierung

Sowohl SORT_STRING als auch SORT_REGULAR beachten die Groß-/Kleinschreibung, weshalb Strings, welche mit großem Buchstaben beginnen, vor Strings einsortiert werden, die mit kleinem Buchstaben anfangen.

Um eine Suche durchzuführen, die die Groß-/Kleinschreibung nicht beachtet, muss man erzwingen, dass die Sortierreihenfolge von einer Kopie des Originalarrays in Kleinschreibung festgelegt wird.

<?php
$array 
= array('Alpha''atomar''Beta''bank');
$array_lowercase array_map('strtolower'$array);

array_multisort($array_lowercaseSORT_ASCSORT_STRING$array);

print_r($array);
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

Array
(
    [0] => Alpha
    [1] => atomar
    [2] => bank
    [3] => Beta
)

Siehe auch


50 BenutzerBeiträge:
- Beiträge aktualisieren...
jimpoz at jimpoz dot com
21.10.2010 23:26
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);
?>
m__faraz at hotmail dot com
8.06.2010 17:10
The last example for multisort an array by a text field works well.
However, it is case sensitive.
So here is my version of the same with case insensitivity.

<?php
$tmp
= Array();
foreach(
$aMultiArray as &$aSingleArray)    $tmp[] = &$aSingleArray["name"];
$tmp = array_map('strtolower', $tmp);
array_multisort($tmp, $aMultiArray);
?>

Hope this helps someone out there.
zequez at gmail dot com
7.05.2010 0:19
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
*/
?>

^-^
alexander dot v at zend dot com
20.01.2010 12:42
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);
?>
d_inkubus at yahoo dot com
22.12.2009 0:33
Update to array_msort()--in PHP 5.3 it won't work.

The solution is to replace the array_merge($params, $order) with the following code snippet:

<?php
$order
=(array)$order;
foreach(
$order as $order_element)
{
   
$params[]=&$order_element;
}
?>

Full code to array_msort():

<?php
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]);
        }
    }
   
$params = array();
    foreach (
$cols as $col => $order)
    {
   
       
$params[] =&$colarr[$col];
       
$order=(array)$order;
        foreach(
$order as $order_element)
        {
           
//pass by reference, as required by php 5.3
           
$params[]=&$order_element;
        }
    }
   
call_user_func_array('array_multisort', $params);
   
$ret = array();
   
$keys = array();
   
$first = true;
    foreach (
$colarr as $col => $arr)
    {
        foreach (
$arr as $k => $v)
        {
            if (
$first)
            {
               
$keys[$k] = substr($k,1);
            }
           
$k = $keys[$k];
           
            if (!isset(
$ret[$k]))
            {
               
$ret[$k] = $array[$k];
            }
           
           
$ret[$k][$col] = $array[$k][$col];
        }
       
$first = false;
    }
    return
$ret;
}
?>

For further reference, see these bug reports:
http://bugs.php.net/bug.php?id=49069
http://bugs.php.net/bug.php?id=49241
s dot i dot g at gmx dot com
10.07.2009 15:21
simple dns mx record sorting

<?php
//getting domain name
list($user, $domain) = split('[@]', $email);
getmxrr($domain, $mx_server, $mx_weight);

//sorting
for($i = 0; $i < count($mx_server); $i++)
{
   
$mx[$i] = array
    (
     
"server" => $mx_server[$i],
     
"weight" => $mx_weight[$i],
    );
}
array_multisort($mx_weight, SORT_ASC, $mx_server, SORT_ASC, $mx);

//display result
print_r($mx);

//usage
$server = $mx[0]["server"];
?>
cagret at gmail dot com
21.06.2009 12:38
Update to array_msort(): instead of eval() using call_user_func_array(). If we get column sorting via $_GET it would be a serious security hole.

Now it also accepts multiple options for each column:

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

Btw. this function is automatically case-insensitive, as you can see use of strtolower().

<?php
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]); }
    }
   
$params = array();
    foreach (
$cols as $col => $order) {
       
$params[] =& $colarr[$col];
       
$params = array_merge($params, (array)$order);
    }
   
call_user_func_array('array_multisort', $params);
   
$ret = array();
   
$keys = array();
   
$first = true;
    foreach (
$colarr as $col => $arr) {
        foreach (
$arr as $k => $v) {
            if (
$first) { $keys[$k] = substr($k,1); }
           
$k = $keys[$k];
            if (!isset(
$ret[$k])) $ret[$k] = $array[$k];
           
$ret[$k][$col] = $array[$k][$col];
        }
       
$first = false;
    }
    return
$ret;

}
?>
cagret at gmail dot com
20.06.2009 21:16
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;

}

?>
m dot michalczyk at gmail dot com
16.05.2009 12:45
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");      
}
?>
za at byza dot it
27.04.2009 19:08
I wrote a function to sort a multidimensional array by multiple columns in ascending and descending order.

Sample array:

<?php
$my_array
=array(
   array(
'id'=>1, 'surname'=>'rossi', 'name'=>'mario', 'group'=>'admin'),
   array(
'id'=>2, 'surname'=>'rossi', 'name'=>'giovanni', 'group'=>'user'),
   array(
'id'=>3, 'surname'=>'verdi', 'name'=>'luigi', 'group'=>'user'),
   array(
'id'=>4, 'surname'=>'verdi', 'name'=>'franco', 'group'=>'guest'),
   array(
'id'=>5, 'surname'=>'bianchi', 'name'=>'mario', 'group'=>'guest')
);
?>

Example: <?php array_sort($my_array,'!group','surname'); ?>

Output: sort the array DESCENDING by group and then ASCENDING by surname. Notice the use of ! to reverse the sort order. Rows order will be: 2,3,5,4,1

The function code:

<?php
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(@
$a[$k]!==@$b[$k]) {
            return
strcmp(@$b[$k],@$a[$k]);
         }
      }
      else if(@
$a[$k]!==@$b[$k]) {
         return
strcmp(@$a[$k],@$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");       
}
?>
mech.cx
28.03.2009 21:04
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;
}

?>
frank at overdrunk dot net
14.01.2009 23:38
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" ),
}
Zbigniew Heintze http://bigweb.pl
27.11.2008 8:36
<?php
/**
 * Sort DB result
 *
 * @param array $data Result of sql query as associative array
 *
 * Rest of parameters are optional
 * [, string $name  [, mixed $name or $order  [, mixed $name or $mode]]]
 * $name string - column name i database table
 * $order integer - sorting direction ascending (SORT_ASC) or descending (SORT_DESC)
 * $mode integer - sorting mode (SORT_REGULAR, SORT_STRING, SORT_NUMERIC)
 *
 * <code>
 * <?php
 * // You can sort data by several columns e.g.
 * $data = array();
 * for ($i = 1; $i <= 10; $i++) {
 *     $data[] = array( 'id' => $i,
 *                      'first_name' => sprintf('first_name_%s', rand(1, 9)),
 *                      'last_name' => sprintf('last_name_%s', rand(1, 9)),
 *                      'date' => date('Y-m-d', rand(0, time()))
 *                  );
 * }
 * $data = sortDbResult($data, 'date', SORT_DESC, SORT_NUMERIC, 'id');
 * printf('<pre>%s</pre>', print_r($data, true));
 * $data = sortDbResult($data, 'last_name', SORT_ASC, SORT_STRING, 'first_name', SORT_ASC, SORT_STRING);    
 * printf('<pre>%s</pre>', print_r($data, true));
 * ?>
 * </code>
 *
 * @return array $data - Sorted data
 */
function sortDbResult(array $data /*$name, $order, $mode*/) {
   
$_argList = func_get_args();
   
$_data = array_shift($_argList);
    if (empty(
$_data)) {
        return
$_data;
    }
   
$_max = count($_argList);
   
$_params = array();
   
$_cols = array();
   
$_rules = array();
    for (
$_i = 0; $_i < $_max; $_i += 3)
    {
       
$_name = (string) $_argList[$_i];
        if (!
in_array($_name, array_keys(current($_data)))) {
            continue;
        }
        if (!isset(
$_argList[($_i + 1)]) || is_string($_argList[($_i + 1)])) {
           
$_order = SORT_ASC;
           
$_mode = SORT_REGULAR;
           
$_i -= 2;
        } else if (
3 > $_argList[($_i + 1)]) {
           
$_order = SORT_ASC;
           
$_mode = $_argList[($_i + 1)];
           
$_i--;
        } else {
           
$_order = $_argList[($_i + 1)] == SORT_ASC ? SORT_ASC : SORT_DESC;
            if (!isset(
$_argList[($_i + 2)]) || is_string($_argList[($_i + 2)])) {
               
$_mode = SORT_REGULAR;
               
$_i--;
            } else {
               
$_mode = $_argList[($_i + 2)];
            }
        }
       
$_mode = $_mode != SORT_NUMERIC
                   
? $_argList[($_i + 2)] != SORT_STRING ? SORT_REGULAR : SORT_STRING
                   
: SORT_NUMERIC;
       
$_rules[] = array('name' => $_name, 'order' => $_order, 'mode' => $_mode);
    }
    foreach (
$_data as $_k => $_row) {
        foreach (
$_rules as $_rule) {
            if (!isset(
$_cols[$_rule['name']])) {
               
$_cols[$_rule['name']] = array();
               
$_params[] = &$_cols[$_rule['name']];
               
$_params[] = $_rule['order'];
               
$_params[] = $_rule['mode'];
            }
           
$_cols[$_rule['name']][$_k] = $_row[$_rule['name']];
        }
    }
   
$_params[] = &$_data;
   
call_user_func_array('array_multisort', $_params);
    return
$_data;
}
?>
oOo at OoO dot com
10.11.2008 9:58
Since the manual doesn't specify so, I want to point out that the SORT_NUMERIC flag does also work correctly if the values are floating point numbers.
Just don't forget to also add the respective SORT_ASC or SORT_DESC flag :)
matt at idizinc dot com
23.10.2008 20:47
I looked on some forms for an answer to this simple problem and couldn't find one so I came up with a solution that may help in some situations.

How do you sort an array by a field in that array and resolve numeric ties randomly?

Code:
<?php

foreach($list as $temp_list)
{
  
$sort_aux[] = ($temp_list['column_to_sort_by']+(rand(1, 9)/10));
}
array_multisort($sort_aux, SORT_NUMERIC, $list);

?>

Example:

$list[]=array('name'=>'Tom', 'score'=>3);
$list[]=array('name'=>'Sam', 'score'=>3);
$list[]=array('name'=>'Joey', 'score'=>1);

Explanation:
I took an existing example found above that shows how to sort an array by one of it's columns/fields.
I just added: "+(rand(1,9)/10)" To randomly add .1 through .9 to their score to resolve the tie. (Obviously this specific example only works if you're sorting by an integer... so you may need to modify it to suit your needs.)

Hope this helps someone.
isp dot php at spspft dot de
19.10.2008 14:44
I would like to report a kind of confusion that arose with the message

Warning: Call-time pass-by-reference has been deprecated; If you would like to pass it by reference, modify the declaration of array_multisort(). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file...

from a line like this:

array_multisort (&$keyarr, &$arr );// sort against this keys

This message is not easily switched off by changing the error reporting level because it's produced at parsinig time -- not execution time.

I think this message is misleading because the arguments are passed by reference ANYWAY in array_multisort.

Anybody encountering this message should know that nothing has to be done, except deleting the ampersands (&).
I was tricked by this message because of couse I wanted to have the *sorted* array back. And couldn't find the ini file nor the declaration of array_multisort.
I think in this description of array_multisort the call by reference should be listed in the definition.

Hope this helps someone
seiffs_at_centrum-dot-cz
18.08.2008 17:53
There have to be two corrections to the php_multisort($data,$keys)

    // Sort Expression
    $i=0;
    $sort='';  //here
    foreach ($keys as $k){
      if($i>0){$sort.=',';}
      $sort.='$cols[\''.$k['key'].'\']'; //and here
      if($k['sort']){$sort.=',SORT_'.strtoupper($k['sort']);}
      if($k['type']){$sort.=',SORT_'.strtoupper($k['type']);}
      $i++;
    }
php {dot} net [arrt] sebble.com
11.05.2008 11:16
I was requiring a PHP function a sort my array data as part of an SQL interpreter for PHP arrays. This is the code I came up with. and works wonderfully.

I hope this helps somebody. If anyone uses this, let me know what you think, if there are any problems with it...

<?

##                ##
##  PHPMultiSort  ##
##                ##
// Takes:
//        $data,  multidim array
//        $keys,  array(array(key=>col1, sort=>desc), array(key=>col2, type=>numeric))

function php_multisort($data,$keys){
 
 
 
 
// List As Columns
 
foreach ($data as $key => $row) {
    foreach (
$keys as $k){
     
$cols[$k['key']][$key] = $row[$k['key']];
    }
  }
 
// List original keys
 
$idkeys=array_keys($data);
 
// Sort Expression
 
$i=0;
  foreach (
$keys as $k){
    if(
$i>0){$sort.=',';}
   
$sort.='$cols['.$k['key'].']';
    if(
$k['sort']){$sort.=',SORT_'.strtoupper($k['sort']);}
    if(
$k['type']){$sort.=',SORT_'.strtoupper($k['type']);}
   
$i++;
  }
 
$sort.=',$idkeys';
 
// Sort Funct
 
$sort='array_multisort('.$sort.');';
  eval(
$sort);
 
// Rebuild Full Array
 
foreach($idkeys as $idkey){
   
$result[$idkey]=$data[$idkey];
  }
  return
$result;
}

###############

// Example Data

$_DATA['table1'][] = array("name" => "Sebastian", "age" => 18, "male" => true);
$_DATA['table1'][] = array("name" => "Lawrence""age" => 16, "male" => true);
$_DATA['table1'][] = array("name" => "Olivia",    "age" => 10, "male" => false);
$_DATA['table1'][] = array("name" => "Dad",       "age" => 50, "male" => true);
$_DATA['table1'][] = array("name" => "Mum",       "age" => 40, "male" => false);
$_DATA['table1'][] = array("name" => "Sebastian", "age" => 56, "male" => true);
$_DATA['table1'][] = array("name" => "Lawrence""age" => 19, "male" => true);
$_DATA['table1'][] = array("name" => "Olivia",    "age" => 24, "male" => false);
$_DATA['table1'][] = array("name" => "Dad",       "age" => 10, "male" => true);
$_DATA['table1'][] = array("name" => "Mum",       "age" => 70, "male" => false);

###############

$res=php_multisort($_DATA['table1'], array(array('key'=>'name'),array('key'=>'age','sort'=>'desc')))
var_dump($res);

/*
array(10) {
  [8]=>
  array(3) {
    ["name"]=>
    string(3) "Dad"
    ["age"]=>
    int(10)
    ["male"]=>
    bool(true)
  }
  [3]=>
  array(3) {
    ["name"]=>
    string(3) "Dad"
    ["age"]=>
    int(50)
    ["male"]=>
    bool(true)
  }
  [1]=>
  array(3) {
    ["name"]=>
    string(8) "Lawrence"
    ["age"]=>
    int(16)
    ["male"]=>
    bool(true)
  }
  [6]=>
  array(3) {
    ["name"]=>
    string(8...
*/
?>
No Spam
23.04.2008 12:02
To sort the array returned e.g. by oci_fetch_all you must divide it in seperate arrays.
Example:
<?php
$rows
=oci_fetch_all($stmt,$results);
?>
now you have several arrays each named by the key name in the sql result.
E.g. array of names, array of streets, array of towns.
To sort the result by e.g. towns you would do the following:
<?php
array_multisort
($results[towns],$results[names],$results[streets]);
?>
Done.
To display the result sorted by towns you could use this:
<?php
print_r
(array("names"=>$results[names],"streets"=>$results[streets],
"towns"=>$result[towns]));
?>
joopm at hotmail dot com
10.04.2008 13:50
@ scott at bartoncomputer dot com

You could also reference the array (if you wanted the original array in the object sorted):

array_multisort($position, SORT_DESC, &$clsVar->data);

Regards, Chr.
nickl at hamiltontampa dot com
24.02.2008 20:02
I believe this should read:

foreach($firstarray as $sortarray){
      $column[] = $sortarray['email'];
}

//sort arrays after loop
array_multisort($column, SORT_ASC, $firstarray);

Otherwise you will get an array is inconsistent err because $column array won't equal $firstarray until the loop completes.

It was the only way I got it to work, then it was fine. If I am wrong please post a correction.
glenn at freebsd dot nl
29.11.2007 19:49
To sort a nested array by column (key/index):

Example: two entries in the nested array:

firstarray[0]['adres'] = "adres1"
firstarray[0]['email'] = "email2"

firstarray[1]['adres'] = "adres2"
firstarray[1]['email'] = "email1"

-----------------------------------------

Without code: output would put adres1/email2 on top

-----------------------------------------

foreach($firstarray as $sortarray)
{
$column[] = $sortarray['email'];
array_multisort($column, SORT_ASC, $firstarray);
}

-----------------------------------------

With code: output would put adres2/email1 on top
scott at bartoncomputer dot com
3.05.2007 19: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.04.2007 12: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.02.2007 22: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.02.2007 17: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
   
/**
    * @desc You really should validate the posted sort direction against a list of valid possibilities.
    *         Options are SORT_ASC, SORT_DESC, etc, as shown in the documentation for array_multisort
    */
   
$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');
   
   
/**
    * @desc Build columns using the values, for sorting in php
    */
   
$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
        )

)

1.12.2006 15: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.09.2006 9: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
4.09.2006 14: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.08.2006 15: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
7.08.2006 14: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.07.2006 14: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.07.2006 13: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.05.2006 18: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, BUÑUEL, ZUBIETA, ÁLVARES

while a MySQL SELECT with ORDER BY nombre ASC will yield

ABADIA, ÁLVARES, ALVEREZ, BUÑUEL, ZUBIETA

as A and Á are considered two different representations of the same letter.
scott - evolove - net - work it out
23.03.2006 4: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.02.2006 16: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
31.01.2006 20: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
5.01.2006 23: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
19.12.2005 20: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.12.2005 1: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.09.2005 15: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
25.09.2005 22: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.07.2005 15: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.06.2005 8: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.04.2005 6: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.04.2005 17: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
7.04.2005 21: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.11.2004 12: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
5.10.2004 16: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.08.2001 7: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



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)