Search code examples
laravelsortingcollectionslaravel-5.3

Laravel collections not sorting


I have the following Eloquent collection:

[
    [
        'id' => 60902,
        'source' => 'M',
        'price'  => 10.15
    ],
    [
        'id' => 57348,
        'source' => 'A',
        'price'  => 12.00
    ],
    [
        'id' => 54472,
        'source' => 'A',
        'price'  => 12.00
    ],
]

I'm trying to sort it with this code:

$items = $items->sort(function (Item $a, Item $b) {
    if ($a->source == 'A') {
        if ($b->source == 'M' || ($b->source == 'A' && $a->price < $b->price)) {
            return 1;
        } elseif ($b->source == 'A' && $a->price == $b->price) {
            return 0;
        } else {
            return -1;
        }
    } else {
        if ($b->source == 'A' || ($b->source == 'M' && $b->price < $a->price)) {
            return -1;
        } elseif ($b->source == 'M' && $b->price == $a->price) {
            return 0;
        } else {
            return 1;
        }
    }
});

However, the original sort order of $items is always the same before and after. The first item (60902) in the list should have been moved from the beginning to the end.

I ran an Xdebug trace and can see that item 60902 returned -1 in the sorting function and the other two items returned 0 because they are equivalent to each other.

This is how I expect the collection to look after sorting:

[
    [
        'id' => 57348,
        'source' => 'A',
        'price'  => 12.00
    ],
    [
        'id' => 54472,
        'source' => 'A',
        'price'  => 12.00
    ],
    [
        'id' => 60902,
        'source' => 'M',
        'price'  => 10.15
    ]
]

Where is my logic messed up here?


Solution

  • The solution to this was ridiculously simple...I just needed to swap 1 and -1 when returning the sort value to get the results I wanted.

    New code looks like this:

    $items = $items->sort(function (Item $a, Item $b) {
        if ($a->source == 'A') {
            if ($b->source == 'M' || ($b->source == 'A' && $a->price < $b->price)) {
                return -1;
            } elseif ($b->source == 'A' && $a->price == $b->price) {
                return 0;
            } else {
                return 1;
            }
        } else {
            if ($b->source == 'A' || ($b->source == 'M' && $b->price < $a->price)) {
                return 1;
            } elseif ($b->source == 'M' && $b->price == $a->price) {
                return 0;
            } else {
                return -1;
            }
        }
    });