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

问题描述

@H_404_0@我有一个关联数组:

    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] => 
            )
     )
@H_404_0@通常应按releaseDate进行排序,但isNewest正确的元素应该排在首位。

@H_404_0@我使用uasort()完成此操作:

    uasort($arr,function($a,$b){
        return $a['isNewest'] - $b['isNewest'];
    });
@H_404_0@有时候isNewest是正确的,但是在此示例中(在我第一次发现此错误的数据条件下),isNewest对于所有条目都是false

@H_404_0@运行以上操作,结果如下:

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] => 
            )
    )
@H_404_0@问题在于,使用uasort()的方式对数组进行排序似乎颠倒了数组的顺序。如果您查看以上两个数组并检查releaseDate,您会明白我的意思。

@H_404_0@如果isNewest对于任何条目都是正确的,则它们将排在第一位,但是其余的数组顺序仍将最终被颠倒。

@H_404_0@我似乎在理解uasort()比较功能如何工作时遇到了一些麻烦。我尝试返回-11,甚至翻转了$a$b参数,但无济于事。

@H_404_0@我在这里做错了什么?我如何在这里正确使用uasort(),以使数组仍然按releaseDate降序排列,但以这样的方式来处理:将isNewest设置为true的条目首先?

@H_404_0@谢谢!

解决方法

您可以使用单个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

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

uasort($array,$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(包括负数,可能会因减法而使排序混乱),因此像在代码块中所做的那样,进行特定比较会更安全。 / p>

,

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

要获得所需的第一(isNewest)和第二(releaseDate)排序结果,可以简单地两次使用uasort-最后使用最高优先级排序。

uasort($input,fn($a,$b) => strtotime($b['releaseDate']) - strtotime($a['releaseDate']));
uasort($input,$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'),$input
);

工作example


提示未来。使用var_export在此处发布数据。因此,我们只需复制/粘贴它即可在代码中使用它。


如果您想在每个子组(isRelease=true)中将releaseDate个候选人放在首位,请翻转uasort或{{ 1}}。