45

Is it possible to use usort to sort multiple fields in a multidimensional array? For example, I want to sort name alphabetically and then from those records I want to sort them by age. Is this possible using sort?

Array ( 
    [0] => Array ( 
        [name] => Jonah 
        [age] => 27 
    )
    [1] => Array (
        [name] => Bianca 
        [age] => 32 
    )
)
user1205775
  • 479
  • 1
  • 4
  • 4
  • possible duplicate of [Sort multidimensional array by multiple keys](http://stackoverflow.com/questions/3232965/sort-multidimensional-array-by-multiple-keys) – salathe Feb 13 '12 at 13:15

3 Answers3

90

How about:

$arr = Array (
    0 => Array (
        'name' => 'Jonah',
        'age' => '27',
    ),
    1 => Array (
        'name' => 'Bianca',
        'age' => '32',
    ),
    2 => Array (
        'name' => 'Jonah',
        'age' => '25',
    ),
    3 => Array (
        'name' => 'Bianca',
        'age' => '35',
    ),
);
function comp($a, $b) {
    if ($a['name'] == $b['name']) {
        return $a['age'] - $b['age'];
    }
    return strcmp($a['name'], $b['name']);
}

usort($arr, 'comp');
print_r($arr);

output:

Array
(
    [0] => Array
        (
            [name] => Bianca
            [age] => 32
        )

    [1] => Array
        (
            [name] => Bianca
            [age] => 35
        )

    [2] => Array
        (
            [name] => Jonah
            [age] => 25
        )

    [3] => Array
        (
            [name] => Jonah
            [age] => 27
        )

)
Toto
  • 89,455
  • 62
  • 89
  • 125
  • Hi, if age want to desc? is it `return $a['age'] + $b['age'];` ? – Swee Hong Jun 07 '21 at 05:32
  • @SweeHong: Use: `return $b['age'] - $a['age'];` – Toto Jun 07 '21 at 06:37
  • if age was a string you can do strcmp($a['age'], $b['age']); – somtam Jan 20 '22 at 11:50
  • 1
    Starting with PHP 7, you can write the compare function with this single line: `return $a['name'] <=> $b['name'] ?: $a['age'] <=> $b['age'];` The explanation is here: https://wiki.php.net/rfc/combined-comparison-operator – Gogowitsch Oct 04 '22 at 15:55
42
usort($arr, function($a, $b)
{
    $name = strcmp($a['name'], $b['name']);
    if($name === 0)
    {
        return $a['age'] - $b['age'];
    }
    return $name;
});
Beau Grantham
  • 3,435
  • 5
  • 33
  • 43
  • Out of curiosity, if I were sorting `name` but it was an integer instead (for example), instead of using `strcmp` what function would you recommend using? – user1205775 Feb 13 '12 at 14:22
  • @user1205775: Just using simple arithmetic operators would work fine. –  Feb 13 '12 at 17:48
19

How about:

<?php

function getRandomName() {
    $possible = "ab";
    $possible_len = strlen($possible);
    $r = '';
    for ($i = 0; $i < 4; $i++) {
        $r .=  substr($possible, mt_rand(0, $possible_len-1), 1);
    }
    return ucfirst($r);
}

$a = array();
for ($i = 0; $i < 10; $i++) {
    $a[] = array('name' => getRandomName(), 'age' => rand(1,10), 'start_order' => $i);
}
$order = array('name' => 'desc', 'age' => 'asc');

print_r($a);

usort($a, function ($a, $b) use ($order) {
    $t = array(true => -1, false => 1);
    $r = true;
    $k = 1;
    foreach ($order as $key => $value) {
        $k = ($value === 'asc') ? 1 : -1;
        $r = ($a[$key] < $b[$key]);
        if ($a[$key] !== $b[$key]) {
            return $t[$r] * $k;
        }

    }
    return $t[$r] * $k;
});

print_r($a);
Sami Ahmed Siddiqui
  • 2,328
  • 1
  • 16
  • 29
Guy Fawkes
  • 2,313
  • 2
  • 22
  • 39
  • 4
    This solution is the best I've found after multiples research ! It works independently on the number of sort parameters you want and in both ascending or descending orders. – GRosay Sep 26 '18 at 08:14
  • 1
    This definitely is the best, most versatile solution! – Dominique Jun 07 '19 at 07:47