正如@derekaug提到的,sort
方法允许我们输入自定义闭包以对集合进行排序。但我认为他的解决方案写起来有点繁琐,所以有这样一种东西会很好:
$collection = collect([/* items */])
$sort = ["column1" => "asc", "column2" => "desc"];
$comparer = $makeComparer($sort);
$collection->sort($comparer);
实际上,可以通过以下$makeComparer
包装器轻松地生成比较闭包:
$makeComparer = function($criteria) {
$comparer = function ($first, $second) use ($criteria) {
foreach ($criteria as $key => $orderType) {
// normalize sort direction
$orderType = strtolower($orderType);
if ($first[$key] < $second[$key]) {
return $orderType === "asc" ? -1 : 1;
} else if ($first[$key] > $second[$key]) {
return $orderType === "asc" ? 1 : -1;
}
}
// all elements were equal
return 0;
};
return $comparer;
};
示例
$collection = collect([
["id" => 1, "name" => "Pascal", "age" => "15"],
["id" => 5, "name" => "Mark", "age" => "25"],
["id" => 3, "name" => "Hugo", "age" => "55"],
["id" => 2, "name" => "Angus", "age" => "25"]
]);
$criteria = ["age" => "desc", "id" => "desc"];
$comparer = $makeComparer($criteria);
$sorted = $collection->sort($comparer);
$actual = $sorted->values()->toArray();
$criteria = ["age" => "desc", "id" => "asc"];
$comparer = $makeComparer($criteria);
$sorted = $collection->sort($comparer);
$actual = $sorted->values()->toArray();
$criteria = ["id" => "asc"];
$comparer = $makeComparer($criteria);
$sorted = $collection->sort($comparer);
$actual = $sorted->values()->toArray();
现在,既然我们在谈论 Eloquent,那么你很有可能也正在使用 Laravel。因此,我们甚至可以将 $makeComparer()
闭包绑定到 IOC 并从那里解析它:
// app/Providers/AppServiceProvider.php
// in Laravel 5.1
class AppServiceProvider extends ServiceProvider
{
/**
* ...
*/
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->bind("collection.multiSort", function ($app, $criteria){
return function ($first, $second) use ($criteria) {
foreach ($criteria as $key => $orderType) {
// normalize sort direction
$orderType = strtolower($orderType);
if ($first[$key] < $second[$key]) {
return $orderType === "asc" ? -1 : 1;
} else if ($first[$key] > $second[$key]) {
return $orderType === "asc" ? 1 : -1;
}
}
// all elements were equal
return 0;
};
});
}
}
现在你可以在任何需要的地方使用它,如下所示:
现在您可以在需要的任何位置使用它,例如:
$criteria = ["id" => "asc"];
$comparer = $this->app->make("collection.multiSort",$criteria);
$sorted = $collection->sort($comparer);
$actual = $sorted->values()->toArray();
$this->valueRetriever($callback)
来创建一个闭包来使用该属性名称......当然,该属性名称必须存在。 - Mark Baker如果您需要对多个列进行sortBy,则可能需要对它们进行空格填充,以确保"ABC"和"DEF"在"AB"和"DEF"之后,因此对于每个列,至少向右填充到该列的长度(除了最后一列之外的所有列)
) - Mark Bakersprintf()
可能会略微更有效率(即如果你运行了10000次,你可能会看到几个微秒的差异)。我评论的原因是,虽然在某些情况下很有用,但我认为sprintf()
是 C 语言的遗物 - 它的语法不直观,除非你非常熟悉它,否则甚至可以使简单的代码变得更难读。在这种情况下,作者使用它来将列值填充到12个字符,因此行为与我的略有不同。你需要进行“自然排序”才能避免这种“带空格的排序”黑客攻击。 - Leith