按多列对多维数组进行排序
Posted
技术标签:
【中文标题】按多列对多维数组进行排序【英文标题】:Sort multidimensional array by multiple columns 【发布时间】:2011-03-15 01:28:49 【问题描述】:我正在尝试通过多个键对多维数组进行排序,但我不知道从哪里开始。我查看了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'],
]
【问题讨论】:
……你想怎么排序? Sorting multidimensional array in php 的可能重复项 【参考方案1】:你需要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);
从 PHP 5.5.0 开始:
array_multisort(array_column($mylist, 'event_type'), SORT_DESC,
array_column($mylist, 'title'), SORT_ASC,
$mylist);
$mylist
现在是:
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',
),
)
【讨论】:
@Rob 我很好奇你会如何排序 date_start 什么是“胶带派对”? 对于 PHP array_column 函数 github.com/ramsey/array_column 的 polyfill。因此,可以在旧版本上使用第二个代码 sn-p 的更优雅的方式。 @gdaniel 请跟我到我的地下室一探究竟。【参考方案2】: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);
【讨论】:
这个答案缺少教育解释。这个答案如何解决OP关于在三列上对多维数组进行排序的问题?【参考方案3】:您可以使用usort
完成此操作。 $cmp_function
参数可以是:
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']);
对于 PHP 5.3 中的任意数量的字段,您可以使用闭包来创建比较函数:
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')))
对于 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')))
【讨论】:
你可以稍微简化嵌套,我认为你需要对日期做更多的事情,但目前看来这种方法是最好的。 示例数组中使用的 '%Y-%m-%d' 格式的好处是字符串比较适用于日期比较。【参考方案4】:我尝试了下面的代码,我成功了
数组代码
$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')
);
调用数组排序函数
$songs = subval_sort($songs,'artist');
print_r($songs);
数组排序函数
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数组逆向排序函数
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;
【讨论】:
这仅按列排序(以一种不优雅的方式),但 OP 的问题要求排序标准涉及三个列值。充其量,这是对另一个问题的正确答案。【参考方案5】:改进@Stijn Leenknegt 的天才代码,这是我的 2 cent 实用函数:
$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 ($diff) return $diff * ($sortDir === 'asc' ? 1 : -1);
【参考方案6】:
如果要对多维数组进行排序
第一个数组是:
$results['total_quote_sales_person_wise']['quote_po'];
第二个是:
$results['total_quote_sales_person_wise']['quote_count'];
这两个多维数组你想一次降序排序然后使用这个代码:
array_multisort($results['total_quote_sales_person_wise']['quote_po'],SORT_DESC, $results['total_quote_sales_person_wise']['quote_count'],SORT_DESC);
【讨论】:
【参考方案7】:PHP7 使用宇宙飞船运算符 (<=>
) 又名“组合比较运算符”或“三路比较运算符”,让多列排序变得超级简单。
资源:https://wiki.php.net/rfc/combined-comparison-operator
按多列排序就像在运算符两侧编写平衡/关系数组一样简单。轻松搞定!
当$a
值在spaceship 运算符的左侧,$b
值在右侧时,使用 ASCending 排序。
当 $b
值在 spaceship 运算符的左侧,$a
值在右侧时,使用 DESCending 排序。
当 spaceship 运算符比较两个数字字符串时,它会将它们作为数字进行比较——因此您可以自动获得自然排序。
我没有使用uasort()
,因为我认为没有必要保留原始索引。
代码:(Demo) -- 按state
ASC 排序,然后是event_type
ASC,然后是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);
输出
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',
),
)
附言PHP7.4 及更高版本的箭头语法 (Demo)...
usort($array, fn($a, $b) =>
[$a['state'], $a['event_type'], $a['date_start']]
<=>
[$b['state'], $b['event_type'], $b['date_start']]
);
array_multisort()
和对每个排序标准调用 array_column()
的等效技术是:(Demo)
array_multisort(
array_column($array, 'state'),
array_column($array, 'event_type'),
array_column($array, 'date_start'),
$array
);
【讨论】:
既然我们都在使用 PHP 7,这应该是正确的答案。【参考方案8】:也许它可以帮助某人:
// 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;
【讨论】:
以上是关于按多列对多维数组进行排序的主要内容,如果未能解决你的问题,请参考以下文章