Conditionally sorting for an even distribution of records
Suppose I have 10 Eloquent model records in an Item
model such as this (represented as JSON for simplicity):
[
{id: 1, name: 'Item 1', featured: false},
{id: 2, name: 'Item 2', featured: true},
{id: 3, name: 'Item 3', featured: false},
{id: 4, name: 'Item 4', featured: false},
{id: 5, name: 'Item 5', featured: false},
{id: 6, name: 'Item 6', featured: false},
{id: 7, name: 'Item 7', featured: true},
{id: 8, name: 'Item 8', featured: false},
{id: 9, name: 'Item 9', featured: false},
{id: 10, name: 'Item 10', featured: true},
]
I want to organize this list first by id
ascending then distributing the records such that every two records where featured = false
is followed by one record where featured = true
.
The result would look like this:
[
{id: 1, name: 'Item 1', featured: false},
{id: 3, name: 'Item 3', featured: false},
{id: 2, name: 'Item 2', featured: true},
{id: 4, name: 'Item 4', featured: false},
{id: 5, name: 'Item 5', featured: false},
{id: 7, name: 'Item 7', featured: true},
{id: 6, name: 'Item 6', featured: false},
{id: 8, name: 'Item 8', featured: false},
{id: 10, name: 'Item 10', featured: true},
{id: 9, name: 'Item 9', featured: false},
]
How would I do this using an Eloquent collection or query?
1 answer
-
answered 2020-11-25 07:26
DigitalDrifter
Here's a working solution using collections (I'm sure it can be cleaned up quite a bit):
$result = collect($items)->sortBy('id')->partition(function ($i) { return $i['featured']; })->pipe(function ($groups) { return $groups->last()->chunk(2)->reduce(function ($carry, $item) use ($groups) { $item->each(function ($i) use ($carry) { $carry->push($i); }); if ($groups->first()->isNotEmpty()) { $carry->push($groups->first()->shift()); } return $carry; }, collect()); });
See it in action here.