skip to Main Content

I have an associate array like this:

$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"],
];

And I’m trying to sort this array by the numeric order of the “year” values of each sub-array, and when the “year” values are the same, sort the sub-arrays by the natural alphanumeric order of the “title” value.

So this is what I did:

 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>";

When I run these code with php 8.2.0, it works totally well as I expected. And the output is:

    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
        )

)

However, when I run the exact same code with php 7.4.33, the result looks very random (especially the array output after the second usort function, not only the alphanumeric order of the “title”s is not working, but also the numeric order of the “year” is messed up). Here is the result:

    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
        )

)

I’m not sure what is going on, and can’t even find any logic or pattern in this result from php 7.4.33.

Does usort() behave differently in php 8.2.0 vs php 7.4.33?

What is php 7.4.33 doing here exactly in this example cause the second result that looks totally non-logical? (Or there is a logic but I didn’t see?)

What should I do to make my code work as how it works in php 8.2.0 while using php 7.4.33?

(additional information: I was running my code using MAMP local server on mac, if that matters).

2

Answers


  1. From the manual:

    Note:
    If two members compare as equal, they retain their original order. Prior to PHP 8.0.0, their relative order in the sorted array was undefined.

    Your problem is that the second sort isn’t "stable" with regard to the elements that compare as equal.

    To fix this, just move the sorting logic into a single function and sort only once:

    usort($all_works, function($work1, $work2) {
        $cmp = $work2["year"] <=> $work1["year"];
        if($cmp == 0)
        {
            $cmp = strnatcmp($work1["title"], $work2["title"]);
        }
        return $cmp;
    });
    
    Login or Signup to reply.
  2. As previously mentioned, PHP8 implemented stable sorting and any versions before that made no promises about preserving the original element order.

    As for cleaning up your code, it can be reduced to the following: (Demo)

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

    The equivalent behavior can be enjoyed with array_multisort() as well: (Demo)

    array_multisort(
        array_column($all_works, 'year'),
        SORT_DESC,
        array_column($all_works, 'title'),
        SORT_STRING | SORT_NATURAL,
        $all_works
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search