Sort multidimensional array by multiple columns Sort multidimensional array by multiple columns php php

Sort multidimensional array by multiple columns


You need array_multisort

$mylist = array(    array('ID' => 1, 'title' => 'Boring Meeting', 'event_type' => 'meeting'),    array('ID' => 2, 'title' => 'Find My Stapler', 'event_type' => 'meeting'),    array('ID' => 3, 'title' => 'Mario Party', 'event_type' => 'party'),    array('ID' => 4, 'title' => 'Duct Tape Party', 'event_type' => 'party'));# get a list of sort columns and their data to pass to array_multisort$sort = array();foreach($mylist as $k=>$v) {    $sort['title'][$k] = $v['title'];    $sort['event_type'][$k] = $v['event_type'];}# sort by event_type desc and then title ascarray_multisort($sort['event_type'], SORT_DESC, $sort['title'], SORT_ASC,$mylist);

As of PHP 5.5.0:

array_multisort(array_column($mylist, 'event_type'), SORT_DESC,                array_column($mylist, 'title'),      SORT_ASC,                $mylist);

$mylist is now:

array (  0 =>   array (    'ID' => 4,    'title' => 'Duct Tape Party',    'event_type' => 'party',  ),  1 =>   array (    'ID' => 3,    'title' => 'Mario Party',    'event_type' => 'party',  ),  2 =>   array (    'ID' => 1,    'title' => 'Boring Meeting',    'event_type' => 'meeting',  ),  3 =>   array (    'ID' => 2,    'title' => 'Find My Stapler',    'event_type' => 'meeting',  ),)


PHP7 Makes sorting by multiple columns SUPER easy with the spaceship operator (<=>) aka the "Combined Comparison Operator" or "Three-way Comparison Operator".

Resource: https://wiki.php.net/rfc/combined-comparison-operator

Sorting by multiple columns is as simple as writing balanced/relational arrays on both sides of the operator. Easy done!

When the $a value is on the left of the spaceship operator and the $b value is on the right, ASCending sorting is used.

When the $b value is on the left of the spaceship operator and the $a value is on the right, DESCending sorting is used.

When the spaceship operator compares two numeric strings, it compares them as numbers -- so you get natural sorting automagically.

I have not used uasort() because I don't see any need to preserve the original indexes.

Code: (Demo) -- sorts by state ASC, then event_type ASC, then date_start ASC

$array = [    ['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],    ['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],    ['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],    ['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']];usort($array, function($a, $b) {    return [$a['state'], $a['event_type'], $a['date_start']]           <=>           [$b['state'], $b['event_type'], $b['date_start']];});var_export($array);

Output

array (  0 =>   array (    'ID' => 4,    'title' => 'Duct Tape Party',    'date_start' => '2010-07-28',    'event_type' => 'party',    'state' => 'california',  ),  1 =>   array (    'ID' => 2,    'title' => 'Find My Stapler',    'date_start' => '2010-07-22',    'event_type' => 'meeting',    'state' => 'new-york',  ),  2 =>   array (    'ID' => 1,    'title' => 'Boring Meeting',    'date_start' => '2010-07-30',    'event_type' => 'meeting',    'state' => 'new-york',  ),  3 =>   array (    'ID' => 3,    'title' => 'Mario Party',    'date_start' => '2010-07-22',    'event_type' => 'party',    'state' => 'new-york',  ),)

p.s. Arrow syntax with PHP7.4 and higher (Demo)...

usort($array, fn($a, $b) =>    [$a['state'], $a['event_type'], $a['date_start']]    <=>    [$b['state'], $b['event_type'], $b['date_start']]);

The equivalent technique with array_multisort() and a call of array_column() for every sorting criteria is: (Demo)

array_multisort(    array_column($array, 'state'),    array_column($array, 'event_type'),    array_column($array, 'date_start'),    $array);


You can do it with usort. The $cmp_function argument could be:

function my_sorter($a, $b) {    $c = strcmp($a['state'], $b['state']);    if($c != 0) {        return $c;    }    $c = strcmp($a['event_type'], $b['event_type']);    if($c != 0) {        return $c;    }    return strcmp($a['date_start'], $b['date_start']);}

For an arbitrary number of fields in PHP 5.3, you can use closures to create a comparison function:

function make_cmp($fields, $fieldcmp='strcmp') {    return function ($a, $b) use (&$fields) {        foreach ($fields as $field) {            $diff = $fieldcmp($a[$field], $b[$field]);            if($diff != 0) {                return $diff;            }        }        return 0;    }}usort($arr, make_cmp(array('state', 'event_type', 'date_start')))

For an arbitrary number of fields of different types in PHP 5.3:

function make_cmp($fields, $dfltcmp='strcmp') {    # assign array in case $fields has no elements    $fieldcmps = array();    # assign a comparison function to fields that aren't given one    foreach ($fields as $field => $cmp) {        if (is_int($field) && ! is_callable($cmp)) {            $field = $cmp;            $cmp = $dfltcmp;        }        $fieldcmps[$field] = $cmp;    }    return function ($a, $b) use (&$fieldcmps) {        foreach ($fieldcmps as $field => $cmp) {            $diff = call_user_func($cmp, $a[$field], $b[$field]);            if($diff != 0) {                return $diff;            }        }        return 0;    }}function numcmp($a, $b) {    return $a - $b;}function datecmp($a, $b) {    return strtotime($a) - strtotime($b);}/** * Higher priority come first; a priority of 2 comes before 1. */function make_evt_prio_cmp($priorities, $default_priority) {    return function($a, $b) use (&$priorities) {        if (isset($priorities[$a])) {            $prio_a = $priorities[$a];        } else {            $prio_a = $default_priority;        }        if (isset($priorities[$b])) {            $prio_b = $priorities[$b];        } else {            $prio_b = $default_priority;        }        return $prio_b - $prio_a;    };}$event_priority_cmp = make_evt_prio_cmp(    array('meeting' => 5, 'party' => 10, 'concert' => 7),     0);usort($arr, make_cmp(array('state', 'event' => $event_priority_cmp, 'date_start' => 'datecmp', 'id' => 'numcmp')))