如何通过 asc 和 desc 的多个属性对 Laravel 集合进行排序?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/47319120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I sort a Laravel Collection by multiple properties with both asc and desc?
提问by Tarek Adam
If I have an Illuminate\Support\Collection, how do I sort by multiple properties with both asc and desc? (This is a simple hypothetical - not at all looking for tips on query building.)
如果我有一个 Illuminate\Support\Collection,我如何使用 asc 和 desc 按多个属性排序?(这是一个简单的假设 - 根本不寻找有关查询构建的提示。)
$collection = User::all(); // not looking for User::orderBy()->get() solutions. Read the question.
$sorting_insructions = [
['column'=>'first_name', 'order'=>'asc'],
['column'=>'date_of_birth', 'order'=>'desc'],
];
$collection->sort(function($a,$b) use ($sorting_instructions){
// something...
});
采纳答案by Tarek Adam
Whoever uses this, just keep in mind - you'll need to tweak it depending if your using collection of objects or associative arrays. Should be an easy tweak. Just change the $a[]/$b[] stuff to $a-> and $b->
无论谁使用它,请记住 - 您需要根据您使用的对象集合还是关联数组来调整它。应该是一个简单的调整。只需将 $a[]/$b[] 内容更改为 $a-> 和 $b->
public static function multiPropertySort(Collection $collection, array $sorting_instructions){
return $collection->sort(function ($a, $b) use ($sorting_instructions){
//stuff starts here to answer question...
foreach($sorting_instructions as $sorting_instruction){
$a[$sorting_instruction['column']] = (isset($a[$sorting_instruction['column']])) ? $a[$sorting_instruction['column']] : '';
$b[$sorting_instruction['column']] = (isset($b[$sorting_instruction['column']])) ? $b[$sorting_instruction['column']] : '';
if(empty($sorting_instruction['order']) or strtolower($sorting_instruction['order']) == 'asc'){
$x = ($a[$sorting_instruction['column']] <=> $b[$sorting_instruction['column']]);
}else{
$x = ($b[$sorting_instruction['column']] <=> $a[$sorting_instruction['column']]);
}
if($x != 0){
return $x;
}
}
return 0;
})->values();
}
回答by YouneL
If you are using Eloquent to get your collection instance, It would be much better to use orderBy methodin your query, especially if columns were indexed:
如果您正在使用 Eloquent 来获取您的集合实例,那么在您的查询中使用orderBy 方法会更好,特别是如果列被索引:
$sorting_insructions = [
['column'=>'first_name', 'order'=>'asc'],
['column'=>'date_of_birth', 'order'=>'desc'],
];
$collection = App\User::query();
foreach ($sorting_insructions as $value) {
$collection->orderBy($value['column'], $value['order']);
}
$users = $collection->get();
EDITSince the question was edited telling that sort should be used outside the query builder, I think chaining sortByand sortByDescin reverse order from $sorting_insructions
gives the same result:
编辑由于编辑了问题,告诉排序应该在查询构建器之外使用,我认为以相反的顺序链接sortBy和sortByDesc$sorting_insructions
给出相同的结果:
$collection = App\User::all();
$sorting_insructions = [
['column'=>'first_name', 'order'=>'asc'],
['column'=>'date_of_birth', 'order'=>'desc'],
];
for ($i = count($sorting_insructions) - 1; $i >= 0 ; $i--) {
extract($sorting_insructions[i]);
if ( $order === 'asc') {
$collection = $collection->sortBy( $column );
} else {
$collection = $collection->sortByDesc( $column );
}
}
回答by Piterden
public static function multiPropertySort(
Collection $collection,
array $rules
)
{
return $collection->sort(
function ($a, $b) use ($rules) {
foreach($rules as $rule){
$sortColumn = array_get($rule, 'column');
array_set(
$a,
$sortColumn,
array_get($a, $sortColumn, '')
);
array_set(
$b,
$sortColumn,
array_get($b, $sortColumn, '')
);
if ($sortOrder = array_get($rule, 'order', 'asc')) {
$x = (array_get($a, $sortColumn) <=> array_get($b, $sortColumn));
} else {
$x = (array_get($b, $sortColumn) <=> array_get($a, $sortColumn));
}
if ($x != 0) {
return $x;
}
}
return 0;
}
);
}
Let's imagine something imperative...
让我们想象一些势在必行的事情......
回答by NoOorZ24
It's a while after this question was asked and I'm not sure it's a best way to do this (because of many loops) but it's really short code.
在问这个问题之后过了一段时间,我不确定这是最好的方法(因为有很多循环),但它的代码真的很短。
$sortDrives = $drives->groupBy('date')->sortBy('date');
$lastDrive = $sortDrives->map(function ($item, $key) {
return $item->sortBy('odometer');
})->collapse()->last();
I pasted my own example as logic is simple enough to edit it
我粘贴了我自己的例子,因为逻辑很简单,可以编辑它
Explanation:
解释:
Lets say: date1 < date2and odometer1 < odometer2 < odometer3
让我们说:date1 < date2和odometer1 < odometer2 < odometer3
At first you turn:
首先你转:
[
0 => ['date' => date2, 'odometer' => odometer3],
1 => ['date' => date1, 'odometer' => odometer2],
2 => ['date' => date1, 'odometer' => odometer1],
]
Into:
进入:
[
date2 => [
0 => ['date' => date2, 'odometer' => odometer3]
],
date1 => [
0 => ['date' => date1, 'odometer' => odometer2],
1 => ['date' => date1, 'odometer' => odometer1]
]
]
Then you sort it by new key and get:
然后您按新键对其进行排序并得到:
[
date1 => ...
date2 => ...
]
After that you sort by key #2 insideeach array date key is pointing at:
之后,你按#键2内每个阵列日期键正指向:
[
date1 => [
0 => ['date' => date1, 'odometer' => odometer1],
1 => ['date' => date1, 'odometer' => odometer2]
]
date2 => [
0 => ['date' => date2, 'odometer' => odometer3]
],
]
An finally you just collide all those arrays together (removing date key) and get:
最后,您只需将所有这些数组碰撞在一起(删除日期键)并得到:
[
0 => ['date' => date1, 'odometer' => odometer1],
1 => ['date' => date1, 'odometer' => odometer2],
2 => ['date' => date2, 'odometer' => odometer3]
]