Sort multidimensional array by multiple keys

2019-01-01 05:41发布

问题:

I\'m trying to sort a multidimensional array by multiple keys, and I have no idea where to start. I looked at uasort, but wasn\'t quite sure how to write a function for what I need.

I need to sort by the state, then event_type, then date.

My array looks like this:

    Array
(
    [0] => Array
        (
            [ID] => 1
            [title] => Boring Meeting
            [date_start] => 2010-07-30
            [time_start] => 06:45:PM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [1] => Array
        (
            [ID] => 2
            [title] => Find My Stapler
            [date_start] => 2010-07-22
            [time_start] => 10:45:AM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [2] => Array
        (
            [ID] => 3
            [title] => Mario Party
            [date_start] => 2010-07-22
            [time_start] => 02:30:PM
            [time_end] => 07:15:PM
            [state] => new-york
            [event_type] => party
        )

    [3] => Array
        (
            [ID] => 4
            [title] => Duct Tape Party
            [date_start] => 2010-07-28
            [time_start] => 01:00:PM
            [time_end] => 
            [state] => california
            [event_type] => party
        )
...... etc

回答1:

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 asc
array_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\',
  ),
)


回答2:

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\')))


回答3:

class Sort {
    private $actual_order = \'asc\';
    private $actual_field = null;

    public function compare_arrays($array1, $array2) {

        if ($array1[$this->actual_field] == $array2[$this->actual_field]) {
            return 0;
        }
        elseif ($array1[$this->actual_field] > $array2[$this->actual_field]) {
            return ($this->actual_order == \'asc\' ? 1 : -1);
        }
        else {
            return ($this->actual_order == \'asc\' ? -1 : 1);
        }

    }


    public function order_array(&$array) {

        usort($array, array($this, \'compare_arrays\'));

    }


    public function __construct ($field, $actual_order = \'asc\') {
        $this->actual_field = $field;
        $this->actual_order = $actual_order;
    }

}

// use

$sort = new Sort (\"state\");

$sort->order_array($array);


回答4:

I have tried to below code and i successfully

array code

$songs =  array(
        \'1\' => array(\'artist\'=>\'Smashing Pumpkins\', \'songname\'=>\'Soma\'),
        \'2\' => array(\'artist\'=>\'The Decemberists\', \'songname\'=>\'The Island\'),
        \'3\' => array(\'artist\'=>\'Fleetwood Mac\', \'songname\' =>\'Second-hand News\')
);

call array sorting function

$songs = subval_sort($songs,\'artist\'); 
print_r($songs);

array sorting funcation

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[] = $a[$key];
    }
    return $c;
}

if array reverse sorting function

function subval_sort($a,$subkey) {
        foreach($a as $k=>$v) {
            $b[$k] = strtolower($v[$subkey]);
        }
        arsort($b);
        foreach($b as $key=>$val) {
            $c[] = $a[$key];
        }
        return $c;
    }


回答5:

Improving on @Stijn Leenknegt\'s genius code, here is my 2 cent pragmatic function:

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

function make_cmp(array $sortValues)
{
    return function ($a, $b) use (&$sortValues) {
        foreach ($sortValues as $column => $sortDir) {
            $diff = strcmp($a[$column], $b[$column]);
            if ($diff !== 0) {
                if (\'asc\' === $sortDir) {
                    return $diff;
                }
                return $diff * -1;
            }
        }
        return 0;
    };
}

usort($data, make_cmp([\'volume\' => \"desc\", \'edition\' => \"asc\"]));


回答6:

if you want to sort multi dimentional array

first array is :

$results[\'total_quote_sales_person_wise\'][\'quote_po\'];

second one is :

$results[\'total_quote_sales_person_wise\'][\'quote_count\'];

this both multidimentional array you want to sort descending order at one time then use this code :

array_multisort($results[\'total_quote_sales_person_wise\'][\'quote_po\'],SORT_DESC, $results[\'total_quote_sales_person_wise\'][\'quote_count\'],SORT_DESC);