usort changing Array's order
Asked Answered
S

3

5

I have a usort function with a single line: return 0.
I tried to use it on an Array of stdClass objects, and it changes
their order, how is that possible?

Snelling answered 2/9, 2011 at 13:7 Comment(3)
tried it with uasort as well, still changed the orderSnelling
pastebin.com/JPvvxJaC - change the uasort to usort, it will still change the orderSnelling
PHP8 implemented stable sorting.Valval
H
11

The property you assume is called stability: A stable sorting algorithm will not change the order of elements that are equal.

php's sorting functions are not stable (because non-stable sorts may be slightly faster). From the documentation of usort:

If two members compare as equal, their order in the sorted array is undefined.

If you want a stable sorting algorithm, you must implement it yourself.

Heartbreaking answered 2/9, 2011 at 13:15 Comment(1)
Thanks for this! FYI though (with PHP 7.1.9): "Type error: array_slice() expects parameter 2 to be integer, float given". It seems to be fixed by using $halfway = intval(count($array) / 2); instead, but I'm not sure if this screws something else up (is it important to slice the array exactly in the middle?)Paola
L
1

It's because that function means "I really don't care how they are sorted, they are equal to me". With this simple sample I receive reversed array:

function sortaaa($a,$b) {return 0;}
$array = array(1,2,3,4,5);
usort($array,"sortaaa");
var_dump($array);
//prints array(5) { [0]=> int(5) [1]=> int(4) [2]=> int(3) [3]=> int(2) [4]=> int(1) }

So it looks like PHP loops the array in reverse order in function usort. So, note the usort manual states that

If two members compare as equal, their order in the sorted array is undefined.

Lining answered 2/9, 2011 at 13:11 Comment(3)
what would you suggest as a solution?Snelling
That depends on what do you mean by solution. What do you want to achieve?Lining
@Snelling If stability is such an issue, roll out your own sorting routine. Added a link to one to my answer.Heartbreaking
B
1

If you're looking for a quick solution for a stable usort, you could use uksort like in the following example:

<?php

uksort($array, function ($ak, $bk) use ($array) {
    $a = $array[$ak];
    $b = $array[$bk];

    if ($a['foo'] === $b['foo']) 
        return $ak - $bk;

    return $a['foo'] > $b['foo'] ? 1 : -1;
});

This works as expected only if the initial indices (keys) of $array are in ascending order.

Bolding answered 12/9, 2018 at 17:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.