m4gix1
m4gix1

Reputation: 336

Sorting laravel collection by leaving null/empty last

Can't seem to get my head around of sorting laravel collection so empty / null data would end up being last. ( bit confused about usort )

Pretty much all I have is bunch of times / timestamps that need to be ordered. Some rows may not have for that column.

I would like data to appear ASC / ascending while empty/null data is shown last.

$collection->sortBy('timestamp') sorts nicely but doesn't know how to deal with empty fields.

data

Table looks like this.

   $data = $data->sort(function($a, $b) use ($sortBy) {
        if ($a->{$sortBy} and $b->{$sortBy}) return 0; 
        return ($a->{$sortBy} > $b->{$sortBy}) ? -1 : 1;
    }); 

Random code I tried from the internet, which I can't get to work correctly. $sortBy contains a field name to sort by ( since it may change ) Faulty code deals with empty / null data but its out of order. faulty

Upvotes: 3

Views: 8464

Answers (5)

wivku
wivku

Reputation: 2683

Similar to Mr. Speelman's solution, but as a shorter PHP 7.4+ version:

$collection->sortBy(fn($e) => $e->timestamp ?: PHP_INT_MAX)

Upvotes: 1

Derk Jan Speelman
Derk Jan Speelman

Reputation: 11949

I had a similar issue. In my case, the time attribute of a $result might be NULL. It acts as if NULL is 0 (as int) and that's expected behavior. But I also wanted to sort the collection by leaving NULL last.

$collection->sortBy(function ($result) {
    if ($result['time'] === NULL) {
        return PHP_INT_MAX;
    }

    return $result['time'];
});

You can achieve this simply by returning an value higher in the alphabetical order compared to all other values in the array. i.e. PHP_INT_MAX to be safe. This will make sure all the results where the time equals NULL are at the end of the array.

Upvotes: 3

Jeff S
Jeff S

Reputation: 71

Have to use sort() with a closure. Below will sort timestamp ASC with NULL at the end.

$sorted = $collection->sort(function ($a, $b) {
    if (!$a->timestamp) {
        return !$b->timestamp ? 0 : 1;
    }
    if (!$b->timestamp) {
        return -1;
    }
    if ($a->timestamp == $b->timestamp) {
        return 0;
    }

    return $a->timestamp < $b->timestamp ? -1 : 1;
});

Upvotes: 7

Jakub Kratina
Jakub Kratina

Reputation: 664

Try:

$collection->sortBy('-timestamp')

Does it work?

Upvotes: 3

Pankit Gami
Pankit Gami

Reputation: 2553

I assume your timestamp is unix timestamp.

You can sort it like this :

$sorted = $collection->sortByDesc('timestamp');

Upvotes: -3

Related Questions