tuck/sort

PHP 排序的语法糖

v0.1.0 2018-05-28 19:20 UTC

This package is auto-updated.

Last update: 2024-09-12 03:46:10 UTC


README

Build Status Latest Stable Version Total Downloads License

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()。或者 natsortnatcasesort,它们总是保留原始键。你明白我的意思。

使用这个库,返回的键会被重置为连续数字,不管排序的类型是什么。

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)决定。没有简单的方法可以标准化这一点(我已经尝试过了),但它会根据运行时、数组中的元素数量、使用的排序算法等因素而变化。好消息是,如果元素是随机的,这也无关紧要,因为没有值得排序的任何东西! :)

许可证

MIT

贡献

欢迎PR。 :) 请遵守PSR-2,使用测试,并尊重代码宣言

状态

正在工作,已测试,但仍需添加非功能性内容,如文档和漂亮的README徽章。