按多列对多维数组进行排序

我试着用多个键对一个多维数组进行排序,但是我不知道从哪里开始。我查看了 uasort(),但不太确定如何为我需要的内容编写函数。

我需要按 state排序,然后是 event_type,然后是 date_start

我的数组是这样的:

[
['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']
]

我期望的结果是:

[
['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party',   'state' => 'california']
['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 1, 'title' => 'Boring Meeting',  'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
['ID' => 3, 'title' => 'Mario Party',     'date_start' => '2010-07-22', 'event_type' => 'party',   'state' => 'new-york'],
]
88923 次浏览

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',
),
)
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);

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

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

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"]));

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

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

Maybe it helps someone:

// data to sort
$output = 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')
);


// multi column, multi direction order by
$body['order_by'] = array(
array("field"=> "event_type", "order"=> "desc"),
array("field"=> "title", "order"=> "asc"),
array("field"=> "ID", "order"=> "asc"),
);


$output = $this->multiColumnMultiDirectionSort($body, $output);




public function multiColumnMultiDirectionSort(array $body, array $output)
{
// get order fields and its direction in proper format
$orderFieldDirection = [];
if (!empty($body['order_by']) && is_array($body['order_by'])) {
foreach ($body['order_by'] as $order) {
$orderDirection = $order['order'] == "desc" ? SORT_DESC : SORT_ASC; // we need format that array_multisort supports
$orderFieldDirection[$order['field']] = $orderDirection;
}
}


if (!empty($orderFieldDirection)) {
// get the list of sort columns and their data in the format that is required by array_multisort
$amParams = [];
$sort = [];
foreach ($orderFieldDirection as $field => $order) {
foreach ($output as $k => $v) {
$sort[$field][$k] = $v[$field];
}


$amParams[] = $sort[$field];
$amParams[] = $order;
$amParams[] = SORT_REGULAR; // this is not needed, but we can keep as it might come handy in the future
}


$amParams[] = &$output; // very important to pass as reference
call_user_func_array("array_multisort", $amParams);
}


return $output;
}