为什么使用比较函数按布尔值对关联数组进行排序会反转数组顺序?

Why does sorting an associative array by a boolean value using a comparison function reverse the array order?

我有一个关联数组:

    Array(

        [110] => Array
            (
                [releaseDate] => 2020-08-15 00:00:00
                [isNewest] => 
            )
        [128] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [129] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [130] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [132] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [123] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [124] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [125] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [127] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
     )

通常这应该按 releaseDate 排序,但 isNewest 为真的元素应该排在第一位。

我使用 uasort() 来完成:

    uasort($arr, function($a, $b){
        return $a['isNewest'] - $b['isNewest'];
    });

有时 isNewest 是正确的,但在这个例子中(以及在数据条件下我首先发现了这个错误)isNewest 对于所有条目都是 false

运行以上,这是结果:

Array
    (
        [124] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [125] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [127] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [123] => Array
            (
                [releaseDate] => 2020-07-01 00:00:00
                [isNewest] => 
            )
        [132] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [128] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [129] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )
        [130] => Array
            (
                [releaseDate] => 2020-08-01 00:00:00
                [isNewest] => 
            )

        [110] => Array
            (
                [releaseDate] => 2020-08-15 00:00:00
                [isNewest] => 
            )
    )

问题是按照我的方式对数组进行排序,使用 uasort() 似乎颠倒了数组顺序。如果你查看上面的两个数组并检查 releaseDate,你就会明白我的意思了。

如果 isNewest 对任何条目都为真,则它们会排在第一位,但数组顺序的其余部分最终仍会被颠倒。

我似乎无法理解 uasort() 比较功能的工作原理。我尝试返回 -11,甚至翻转 $a$b 参数,但无济于事。

我在这里做错了什么?我如何在这里正确使用 uasort(),以便数组保持按 releaseDate 降序排序,但是这样 isNewest 设置为 true 的条目就会出现第一个?

谢谢!

当每个isNewest设置为false时,我无法reproduce反转。

为了得到你想要的第一个(isNewest)和第二个(releaseDate)顺序排序的结果,你可以简单地使用 uasort 两次 - 最后使用最高优先级排序。

uasort($input, fn($a, $b) => strtotime($b['releaseDate']) - strtotime($a['releaseDate']));
uasort($input, fn($a, $b) => $b['isNewest'] - $a['isNewest']);

工作example


您也可以使用 array_multisort 以防您不需要密钥。 (数字键将丢失)。

array_multisort(
    array_column($input, 'isNewest'),
    SORT_DESC, // 1 before 0 (true before false)
    array_column($input, 'releaseDate'),
    SORT_DESC,
    $input
);

工作example


未来的小费。此处使用 var_export 到 post 数据。所以我们可以简单地copy/paste它在代码中使用它。


如果你想让 isRelease=true 个候选人在每个 sub-group(releaseDate)中排在首位 - 翻转 uasortarray_columnsarray_multisort.

您可以使用单个 uasort 调用对数据进行排序,首先检查日期是否相等(如果不相等,则返回排序结果),然后首先对 true 值进行排序:

uasort($array, function ($a, $b) {
    // if dates not equal, return result of comparison
    // since dates are in Y-m-d H:i:s format we can compare as strings
    if (($rdcmp = strcmp($a['releaseDate'], $b['releaseDate'])) != 0) return $rdcmp;
    // dates are equal, so sort true values first
    if ($a['isNewest'] && !$b['isNewest']) return -1;
    elseif (!$a['isNewest'] && $b['isNewest']) return 1;
    else return 0;
});
print_r($array);

Demo on 3v4l.org

或者要对false之前的所有true值进行排序,然后按releaseDate排序,可以使用此代码:

uasort($array, function ($a, $b) {
    // sort true values first
    if ($a['isNewest'] && !$b['isNewest']) return -1;
    elseif (!$a['isNewest'] && $b['isNewest']) return 1;
    // boolean values are equal, so sort by date. 
    // Since dates are in Y-m-d H:i:s format, we can sort as strings
    else return strcmp($a['releaseDate'], $b['releaseDate']);
});

Demo on 3v4l.org

请注意,如果您想按 releaseDate 降序排序,您应该更改

strcmp($a['releaseDate'], $b['releaseDate'])

strcmp($b['releaseDate'], $a['releaseDate'])

还要注意如果你的布尔值实际上是truefalse,你可以简化布尔值比较

return $b['isNewest'] - $a['isNewest'];

否则,由于 PHP 将所有类型的值都视为 true(包括负数,这可能会弄乱减法排序),像我所做的那样进行特定比较更安全在代码块中。