usort() 在 php 8.2.0 与 php 7.4.33 中的行为是否不同?

问题描述 投票:0回答:2

我有一个像这样的关联数组:

$all_works = [
    ["title"=>"A Children’s Story", "year"=>"2024"],
    ["title"=>"Occurred during the Day", "year"=>"2021"],
    ["title"=>"Future and Past", "year"=>"2021"],
    ["title"=>"Future and History", "year"=>"2020"],
    ["title"=>"Open the School, Close the Studio", "year"=>"2023"],
    ["title"=>"To Reconstruct, To Rebuild", "year"=>"2024"],
    ["title"=>"Eyeglasses, a Story", "year"=>"2023"],
    ["title"=>"Nomadic Life", "year"=>"2024"],
    ["title"=>"Chipotle!", "year"=>"2022"],
    ["title"=>"between Art & Technology", "year"=>"2020"],
    ["title"=>"interview Script", "year"=>"2018"],
    ["title"=>"memories and confession", "year"=>"2024"],
    ["title"=>"Guest of Pluto", "year"=>"2022"],
    ["title"=>"A Prologue", "year"=>"2022"],
    ["title"=>"You are in this place", "year"=>"2023"],
    ["title"=>"Happening Now", "year"=>"2024"],
    ["title"=>"Review Catalogue", "year"=>"2022"],
    ["title"=>"A living being of Mars", "year"=>"2021"],
];

我尝试按每个子数组的“年份”值的数字顺序对该数组进行排序,当“年份”值相同时,按“的自然字母数字顺序对子数组进行排序”标题”值。

所以这就是我所做的:

 usort($all_works, function($work1, $work2) {
    return $work2["year"] <=> $work1["year"];
});
echo "<br><br>";
echo "<pre>";
print_r($all_works);
echo "</pre>";

usort($all_works, function($work3, $work4){
    if($work3["year"] == $work4["year"]){
        return strnatcmp($work3["title"], $work4["title"]);
    }else{
        return 0;
    }
});
echo "<br><br>";
echo "<pre>";
print_r($all_works);
echo “</pre>";

当我使用 php 8.2.0 运行这些代码时,它的工作效果完全符合我的预期。输出是:

    Array
(
    [0] => Array
        (
            [title] => A Children’s Story
            [year] => 2024
        )

    [1] => Array
        (
            [title] => To Reconstruct, To Rebuild
            [year] => 2024
        )

    [2] => Array
        (
            [title] => Nomadic Life
            [year] => 2024
        )

    [3] => Array
        (
            [title] => memories and confession
            [year] => 2024
        )

    [4] => Array
        (
            [title] => Happening Now
            [year] => 2024
        )

    [5] => Array
        (
            [title] => Open the School, Close the Studio
            [year] => 2023
        )

    [6] => Array
        (
            [title] => Eyeglasses, a Story
            [year] => 2023
        )

    [7] => Array
        (
            [title] => You are in this place
            [year] => 2023
        )

    [8] => Array
        (
            [title] => Chipotle!
            [year] => 2022
        )

    [9] => Array
        (
            [title] => Guest of Pluto
            [year] => 2022
        )

    [10] => Array
        (
            [title] => A Prologue
            [year] => 2022
        )

    [11] => Array
        (
            [title] => Review Catalogue
            [year] => 2022
        )

    [12] => Array
        (
            [title] => Occurred during the Day
            [year] => 2021
        )

    [13] => Array
        (
            [title] => Future and Past
            [year] => 2021
        )

    [14] => Array
        (
            [title] => A living being of Mars
            [year] => 2021
        )

    [15] => Array
        (
            [title] => Future and History
            [year] => 2020
        )

    [16] => Array
        (
            [title] => between Art & Technology
            [year] => 2020
        )

    [17] => Array
        (
            [title] => interview Script
            [year] => 2018
        )

)


Array
(
    [0] => Array
        (
            [title] => A Children’s Story
            [year] => 2024
        )

    [1] => Array
        (
            [title] => Happening Now
            [year] => 2024
        )

    [2] => Array
        (
            [title] => Nomadic Life
            [year] => 2024
        )

    [3] => Array
        (
            [title] => To Reconstruct, To Rebuild
            [year] => 2024
        )

    [4] => Array
        (
            [title] => memories and confession
            [year] => 2024
        )

    [5] => Array
        (
            [title] => Eyeglasses, a Story
            [year] => 2023
        )

    [6] => Array
        (
            [title] => Open the School, Close the Studio
            [year] => 2023
        )

    [7] => Array
        (
            [title] => You are in this place
            [year] => 2023
        )

    [8] => Array
        (
            [title] => A Prologue
            [year] => 2022
        )

    [9] => Array
        (
            [title] => Chipotle!
            [year] => 2022
        )

    [10] => Array
        (
            [title] => Guest of Pluto
            [year] => 2022
        )

    [11] => Array
        (
            [title] => Review Catalogue
            [year] => 2022
        )

    [12] => Array
        (
            [title] => A living being of Mars
            [year] => 2021
        )

    [13] => Array
        (
            [title] => Future and Past
            [year] => 2021
        )

    [14] => Array
        (
            [title] => Occurred during the Day
            [year] => 2021
        )

    [15] => Array
        (
            [title] => Future and History
            [year] => 2020
        )

    [16] => Array
        (
            [title] => between Art & Technology
            [year] => 2020
        )

    [17] => Array
        (
            [title] => interview Script
            [year] => 2018
        )

)

但是,当我使用 php 7.4.33 运行完全相同的代码时,结果看起来非常随机(特别是第二个 usort 函数之后的数组输出,不仅“title”的字母数字顺序不起作用,而且“年”的数字顺序混乱)。这是结果:

    Array
(
    [0] => Array
        (
            [title] => A Children’s Story
            [year] => 2024
        )

    [1] => Array
        (
            [title] => Happening Now
            [year] => 2024
        )

    [2] => Array
        (
            [title] => To Reconstruct, To Rebuild
            [year] => 2024
        )

    [3] => Array
        (
            [title] => Nomadic Life
            [year] => 2024
        )

    [4] => Array
        (
            [title] => memories and confession
            [year] => 2024
        )

    [5] => Array
        (
            [title] => Open the School, Close the Studio
            [year] => 2023
        )

    [6] => Array
        (
            [title] => Eyeglasses, a Story
            [year] => 2023
        )

    [7] => Array
        (
            [title] => You are in this place
            [year] => 2023
        )

    [8] => Array
        (
            [title] => Guest of Pluto
            [year] => 2022
        )

    [9] => Array
        (
            [title] => Review Catalogue
            [year] => 2022
        )

    [10] => Array
        (
            [title] => Chipotle!
            [year] => 2022
        )

    [11] => Array
        (
            [title] => A Prologue
            [year] => 2022
        )

    [12] => Array
        (
            [title] => A living being of Mars
            [year] => 2021
        )

    [13] => Array
        (
            [title] => Occurred during the Day
            [year] => 2021
        )

    [14] => Array
        (
            [title] => Future and Past
            [year] => 2021
        )

    [15] => Array
        (
            [title] => Future and History
            [year] => 2020
        )

    [16] => Array
        (
            [title] => between Art & Technology
            [year] => 2020
        )

    [17] => Array
        (
            [title] => interview Script
            [year] => 2018
        )

)


Array
(
    [0] => Array
        (
            [title] => A Children’s Story
            [year] => 2024
        )

    [1] => Array
        (
            [title] => Chipotle!
            [year] => 2022
        )

    [2] => Array
        (
            [title] => Future and History
            [year] => 2020
        )

    [3] => Array
        (
            [title] => between Art & Technology
            [year] => 2020
        )

    [4] => Array
        (
            [title] => A living being of Mars
            [year] => 2021
        )

    [5] => Array
        (
            [title] => Future and Past
            [year] => 2021
        )

    [6] => Array
        (
            [title] => Occurred during the Day
            [year] => 2021
        )

    [7] => Array
        (
            [title] => A Prologue
            [year] => 2022
        )

    [8] => Array
        (
            [title] => Guest of Pluto
            [year] => 2022
        )

    [9] => Array
        (
            [title] => Review Catalogue
            [year] => 2022
        )

    [10] => Array
        (
            [title] => Happening Now
            [year] => 2024
        )

    [11] => Array
        (
            [title] => Eyeglasses, a Story
            [year] => 2023
        )

    [12] => Array
        (
            [title] => Open the School, Close the Studio
            [year] => 2023
        )

    [13] => Array
        (
            [title] => You are in this place
            [year] => 2023
        )

    [14] => Array
        (
            [title] => Nomadic Life
            [year] => 2024
        )

    [15] => Array
        (
            [title] => To Reconstruct, To Rebuild
            [year] => 2024
        )

    [16] => Array
        (
            [title] => memories and confession
            [year] => 2024
        )

    [17] => Array
        (
            [title] => interview Script
            [year] => 2018
        )

)

我不确定发生了什么,甚至在 php 7.4.33 的结果中找不到任何逻辑或模式。

usort() 在 php 8.2.0 和 php 7.4.33 中的行为是否不同?

在这个例子中,php 7.4.33 到底在做什么,导致第二个结果看起来完全不合逻辑? (或者有逻辑但我没看到?)

在使用 php 7.4.33 时,我应该怎样做才能使我的代码像在 php 8.2.0 中一样工作?

(附加信息:我在 mac 上使用 MAMP 本地服务器运行我的代码,如果这很重要的话)。

php arrays php-7.4 usort php-8.2
2个回答
5
投票

来自手册

注:
如果两个成员比较相等,则它们保留原来的顺序。在 PHP 8.0.0 之前,它们在排序数组中的相对顺序是未定义的。

您的问题是,对于比较相等的元素,第二种排序并不“稳定”。

要解决此问题,只需将排序逻辑移至单个函数中并仅排序一次:

usort($all_works, function($work1, $work2) {
    $cmp = $work2["year"] <=> $work1["year"];
    if($cmp == 0)
    {
        $cmp = strnatcmp($work1["title"], $work2["title"]);
    }
    return $cmp;
});

0
投票

如前所述,PHP8 实现了稳定排序,之前的任何版本都没有承诺保留原始元素顺序。

至于清理代码,可以简化为以下内容:(Demo

usort($all_works, fn($a, $b) => $a['year'] <=> $b['year'] ?: strnatcmp($a["title"], $b["title"]));

也可以使用

array_multisort()
来享受等效的行为:(演示)

array_multisort(
    array_column($all_works, 'year'),
    array_column($all_works, 'title'),
    SORT_STRING | SORT_NATURAL,
    $all_works
);
© www.soinside.com 2019 - 2024. All rights reserved.