techworker / php-fn-sortby
一个小型函数,可用于对任何形状的数组进行排序。仅支持PHP7。
Requires
- php: >=7
Requires (Dev)
- phpunit/phpunit: ~5.4
This package is auto-updated.
Last update: 2024-08-25 10:17:54 UTC
README
准备一个排序函数,可用于与 usort 结合使用,以函数式方式对任何形状的数组进行排序。
sortBy(..)->thenBy(..)->thenBy(.., \SORT_DESC)
安装
您可以使用 Composer 下载并安装该函数及其依赖项。
只需将 techworker/php-fn-sortby 依赖项添加到您项目的 composer.json 文件中。以下是一个定义对 php-fn-sortby 版本 1.* 的依赖项的最小 composer.json 示例文件。
{ "require": { "techworker/php-fn-sortby": "~1.0" } }
我想您应该知道的一个小缺点,但我会说 OpCache 会解决这个问题。
该库使用 composer 的 autoload->files
来使函数对您可用。在 PHP 中,函数的自动加载不起作用。因此,无论是否使用,文件总是被加载。
当然,您可以下载库并按需 require 它。
定义和用法
首先导入该函数,以便您可以轻松使用或别名它。
// import use function techworker\fn\sortBy; // usage sortBy($criteria1)->thenBy($criteria2)->thenBy($criteria3);
对您可见的唯一函数是 sortBy
。其他一切都是动态创建的函数(或更好的是,实现 techworker\fn\ThenByInterface
的对象),您可以使用与 sortBy
相同的方式使用它们。
定义看起来像这样
sortBy(int|string|callable $comparator[, int $direction = \SORT_ASC[, callable $decorator = null]]) : ThenByInterface
-
string | int | callable $criteria 这可以是字符串或返回排序值的可调用函数。
-
int $direction 排序的方向。这可以是 PHP 中预定义的
SORT_*
常量之一:\SORT_ASC
AND\SORT_DESC
。 -
callable $decorator 可以根据您的
$criteria
应用自定义排序逻辑的装饰器。内置装饰器应该足够强大,可以满足 99% 的情况,因此忽略它将带来良好的结果。如果您需要另一个装饰器,请了解装饰器的作用和使用方法。我们将在文档中省略这一点。
使用字符串作为排序标准
假设我们有一个城市数组,想要按国家升序排序,然后按人口降序排序。
$cities = [ ['name' => 'Shanghai', 'population' => 24256800, 'country' => 'China'], ['name' => 'Karachi', 'population' => 23500000, 'country' => 'Pakistan'], ['name' => 'Beijing', 'population' => 21516000, 'country' => 'China'] ];
这是最简单的用例,我们可以这样做
use function techworker\fn\sortBy; // create a sort callback used for the builtin PHP usort function. $sorter = sortBy('name')->thenBy('population', \SORT_DESC); usort($cities, $sorter);
现在城市数组已排序。您甚至可以使用对象数组。库将尝试通过数组键 [$criteria]
或对象属性 ->{$criteria}
确定值。
使用回调作为排序标准
如果您需要更深入地检索排序标准,可以提供一个函数。
假设您有一个包含部门及其员工的平均工资的部门数组,嵌套如下
$departments = [ 'devops' => [ 'employees' => ['ben', 'peter', 'james', 'lisa', 'tequila'], // 5 'salary' => 4000 ], 'sysop' => [ 'employees' => ['titus', 'raffy', 'ramanda', 'kathleen', 'rufus'], // 5 'salary' => 3000 ], 'mgmt' => [ 'employees' => ['zoey', 'tiny', 'raphael', 'christian', 'michael', 'rene', 'benny', 'johannes', 'sebastian', 'pedro', 'christoph'], // 11 'salary' => 10000 } ];
现在您想按员工数量降序排序,然后按工资降序排序。预期的结果应该如下所示
- mgmt -> 11 员工,10000 薪资
- devop -> 5 员工,4000 薪资
- sysop -> 5 员工,3000 薪资
这是它的工作方式
use function techworker\fn\sortBy; // I declare the callback in variables for better readability $fnNumberEmployees = function($department) { return count($department['employees']); } // create a sort callback used for the builtin PHP usort function. $sorter = sortBy($fnNumberEmployees, \SORT_DESC)->thenBy('salary', \SORT_DESC); usort($departments, $sorter);
如您所知,提供给 usort
的比较函数期望两个参数,并返回一个整数来告诉排序器值是 bigger
(>0),lower
(<0) 还是 equal
(0)。
您使用单个参数封装回调函数的操作由装饰器完成(在初始 sortBy
调用的第三个参数)。
因此,如果您提供了一个仅有一个参数的回调函数(一元),装饰器会自动将其封装,并使用关系运算符 <=>
帮助您完成比较。
如果您提供了两个参数的回调函数,您可以自行进行比较。
以下是一个使用两个参数的回调函数的示例
use function techworker\fn\sortBy; // I declare the callback in variables for better readability $fnNumberEmployees = function($department1, $department2) { return count($department1['employees']) - count($department2['employees']); // or // return count($department1['employees']) <=> count($department2['employees']); } // create a sort callback used for the builtin PHP usort function. $sorter = sortBy($fnNumberEmployees, \SORT_DESC)->thenBy('salary', \SORT_DESC); usort($departments, $sorter);
这应该会给出与上述相同的结果,但您将获得更多关于比较功能本身的控制。
ThenByInterface
sortBy
和 thenBy
函数都返回一个 ThenByInterface
的动态类实例,这使得 IDE 在自动完成调用时更为方便。
请查看实现代码 src,与其他各种解决方案相比,它相当简单。但它看起来很复杂。如果您有任何错误、建议等,请通过 GitHub 的问题与我联系。
希望这对你有所帮助!
致谢
此函数大致移植自 https://github.com/Teun/thenBy.js - 一个具有更多或更少相同功能的 JavaScript 函数。非常感谢这个想法!
移植和增强它的关键问题如下