tuck / sort
PHP 排序的语法糖
Requires
- php: >=7.0
Requires (Dev)
- phpunit/phpunit: ^6.5
This package is auto-updated.
Last update: 2024-09-12 03:46:10 UTC
README
PHP 内置排序的语法糖。
示例
基本排序函数
use Tuck\Sort\Sort; Sort::values(['foo', 'bar', 'baz']); // returns ['bar', 'baz', 'foo'] Sort::keys(['x' => 'foo', 'm' => 'bar']); // returns ['m' => 'bar', 'x' => 'foo'] Sort::natural(['img12.jpg', 'img2.jpg', 'img1.jpg']); // returns ['img1.jpg', 'img2.jpg', 'img12.jpg'] Sort::user( [3, 2, 5, 6], function () { /* custom sorting */ } );
为什么?
这个库试图简化内置 API,特别是以下问题:
PHP 需要变量。
如果你想要对方法的结果进行排序,你需要将其赋值给一个中间变量。
$results = $metrics->getTotals(); sort($results);
使用这个库,你可以直接传递结果
Sort::values($metrics->getTotals());
PHP 修改原地
你可能更喜欢 sort 返回修改后的列表,而不是修改原始列表。不幸的是,sort()
的返回值是一个成功布尔值,而不是重新排序的列表。
使用这个库,结果会直接返回,原始列表不会被修改
$x = [3, 1, 2]; var_dump(Sort::values($x)); // 1, 2, 3 var_dump($x); // 3, 1, 2
PHP 的命名令人困惑
PHP 的排序函数名称并不总是直观
asort() sort() ksort() natsort() usort() uasort() uksort()
使用这个库,命名看起来会好一些
Sort::values() Sort::keys() Sort::natural() Sort::user()
PHP 没有一致地处理键
当你使用 sort()
时,PHP 会丢弃原始键。除非你使用 asort()
。或者 natsort
和 natcasesort
,它们总是保留原始键。你明白我的意思。
使用这个库,返回的键会被重置为连续数字,不管排序的类型是什么。
Sort::values([3 => 'bob', 1 => 'alice']); // returns [0 => 'alice', 1 => 'bob']
如果你想要保留原始键,有一个一致的参数你可以始终使用 Sort::PRESERVE_KEYS
。这在内部选择正确的保留键的函数,这样你就不用记住它了。
Sort::values([3 => 'bob', 1 => 'alice'], Sort::PRESERVE_KEYS); // returns [1 => 'alice', 3 => 'bob']
这适用于所有排序函数
Sort::values(['foo', 'bar', 'baz'], Sort::PRESERVE_KEYS); Sort::natural(['foo', 'bar', 'baz'], Sort::PRESERVE_KEYS); Sort::user( [3, 2, 5, 6], function () { /* custom sorting */ }, Sort::PRESERVE_KEYS );
更容易记住。如果常量太长或难以阅读,你也可以传递 true
来保留键或 false
来丢弃它们。
PHP 不接受迭代器或生成器
内置排序函数在数组上运行得很好,但不会接受它们的可遍历兄弟。
使用这个库,迭代器和生成器会自动转换为数组。
$x = new ArrayIterator([3, 1, 2]); Sort::values($x); // returns [1, 2, 3]
注意,这个库总是返回数组,即使给出的是自定义集合。如果你想让你的自定义集合支持这个库,请参阅下面的 usort 文档。
PHP 没有按字段排序的快捷方式
当你比较一组对象时,你通常想要反复比较它们上的相同字段。通常这意味着编写一个像这样的 usort 函数:
Sort::user($list, function (HighScore $a, HighScore $b) { return $a->getPoints() <=> $b->getPoints(); });
这是在 PHP 7 短语操作符的帮助下完成的。这个库提供了一个稍微简短一些、受 Scala 启发的版本,其中你只需指定如何从一个元素中检索可排序的数据。
Sort::by($list, function (HighScore $a) { return $a->getPoints(); });
这也适用于反向
Sort::byDescending($list, function (HighScore $a) { return $a->getPoints(); });
PHP 没有链式 usort
没有优雅的语法一次链式多个排序。如果你想按分数、姓名、然后按日期对一组高分进行排序,你需要编写一个像这样的函数:
usort( $unsorted, function (HighScore $scoreA, HighScore $scoreB) { $a = $scoreA->getPoints(); $b = $scoreA->getPoints(); if ($a == $b) { $a = $scoreA->getDate(); $b = $scoreB->getDate(); } if ($a == $b) { $a = $scoreA->getName(); $b = $scoreB->getName(); } return $a <=> $b; } );
使用这个库,你可以像这样链式排序
Sort::chain() ->compare(function (HighScore $a, HighScore $b) { return $a->getPoints() <=> $b->getPoints(); }) ->compare(function (HighScore $a, HighScore $b) { return $a->getDate() <=> $b->getDate(); }) ->compare(function (HighScore $a, HighScore $b) { return $a->getName() <=> $b->getName(); });
在大多数情况下,你将想要同时从 $a
和 $b
中提取相同的信息。你也可能想要根据不同的因素按升序或降序对它们进行排序。对于这两个用例,你可以使用 asc()
和 desc()
方法。
$sortChain = Sort::chain() ->desc(function (HighScore $score) { return $score->getPoints(); }) ->asc(function (HighScore $score) { return $score->getDate(); }) ->asc(function (HighScore $score) { return $score->getName(); });
一旦你创建了排序链,就可以将其应用于键或值。支持迭代器支持、返回值和 PRESERVE_KEY 标志等功能。
$sortChain->values(['foo', 'bar']); $sortChain->values(['foo', 'bar'], Sort::PRESERVE_KEYS); $sortChain->keys(['foo' => 'blah', 'bar' => 'blat']);
您还可以将链本身用作比较函数。
$sortChain('steven', 'connie'); // returns -1, 0 or 1
这意味着您可以与任何支持usort的自定义集合类一起使用它。
$yourCustomCollection->usort($sortChain);
在构建排序链时,您不必一次性组合所有排序函数。您可以在任何时候或根据条件附加它们。
$sortOrder = Sort::chain(); if ($options['sort_by_name']) { $sortOrder->asc(...); } // etc
然而,如果您在添加任何排序之前使用链,那么顺序实际上是随机的,由您的PHP运行时(PHP 5.x 与 PHP 7 与 HHVM)决定。没有简单的方法可以标准化这一点(我已经尝试过了),但它会根据运行时、数组中的元素数量、使用的排序算法等因素而变化。好消息是,如果元素是随机的,这也无关紧要,因为没有值得排序的任何东西! :)
许可证
贡献
欢迎PR。 :) 请遵守PSR-2,使用测试,并尊重代码宣言。
状态
正在工作,已测试,但仍需添加非功能性内容,如文档和漂亮的README徽章。