Skip to content

Instantly share code, notes, and snippets.

@matt-allan
Created July 31, 2020 20:49
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save matt-allan/4ce3ba62396c3d71241f0da39ddb88e6 to your computer and use it in GitHub Desktop.
Save matt-allan/4ce3ba62396c3d71241f0da39ddb88e6 to your computer and use it in GitHub Desktop.
Compound sorting Laravel collections

This is an example of sorting a Laravel collection by > 1 attribute with different sort directions. Unlike some of the other solutions mentioned in this thread it works with any type PHP can normally sort and doesn't require hashing.

That works because of how PHP's comparison functions work:

Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are uncomparable, otherwise - compare value by value

The <=> operator is PHP's combined comparison operator, or 'spaceship' operator. It makes writing custom sort functions very easy.

If you need to do a compound sort but every attribute is being sorted in the same direction, you can use sortBy/sortByDesc instead of writing your own sort function.

$taps->sortBy(fn ($tap) => [$tap->rating, $tap->price])
<?php
collect([
(object) [
'name' => 'Ninja Porter',
'price' => 6.00,
'rating' => 4,
],
(object) [
'name' => 'Rocket Girl Lager',
'price' => 6.00,
'rating' => 5,
],
(object) [
'name' => 'Boone Creek Blonde',
'price' => 7.00,
'rating' => 5,
],
(object) [
'name' => 'Pisgah Pale Ale',
'price' => 4.50,
'rating' => 3,
],
])
// Sort by highest rated (rating DESC), lowest price (price ASC)
->sort(fn ($a, $b) => [$b->rating, $a->price] <=> [$a->rating, $b->price])
// Expected sort: Rocket Girl Lager, Boone Creek Blonde, Ninja Porter, Pisgah Pale Ale
->dump();
➜ php artisan tinker example.php
Psy Shell v0.10.4 (PHP 7.4.5 — cli) by Justin Hileman
Illuminate\Support\Collection^ {#5444
  #items: array:4 [
    1 => {#5439
      +"name": "Rocket Girl Lager"
      +"price": 6.0
      +"rating": 5
    }
    2 => {#5440
      +"name": "Boone Creek Blonde"
      +"price": 7.0
      +"rating": 5
    }
    0 => {#5438
      +"name": "Ninja Porter"
      +"price": 6.0
      +"rating": 4
    }
    3 => {#5441
      +"name": "Pisgah Pale Ale"
      +"price": 4.5
      +"rating": 3
    }
  ]
}
>>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment