优雅的方式将雄辩的集合分类为字母组块

I need to sort a collection from my database like this https://www.bodybuilding.com/store/listing.htm

I could write it, but I'd probably also lose the eloquent relationships which isn't ideal.

This feels like something Laravel something can do out of the box, or with very little logic.

Any suggestions?

Checkout the Laravel documentation https://laravel.com/docs/5.7/eloquent#retrieving-models

$listing = App\Store::where('first_letter', 'a')
               ->orderBy('name', 'desc')
               ->take(10)
               ->get();

If you need something more specific, you can always create Scopes and use those in your eloquent models. https://laravel.com/docs/5.7/eloquent#query-scopes

Assuming a model called Categories with a field name and you need to group the categories by the first letter of their name. Each category with a first letter that is not an alphabetic character will be grouped under the '#' symbol:

$collection = Categories::get();
$grouped = $collection->groupBy(function ($item, $key) {
    $letter = $item->name[0];
    if (ctype_alpha($letter)) {
        return $letter;
    }
    return '#';
});

mapToGroups is what I was looking for. Here's my solution.

public function chunkByAlpha(Collection $collection)
{
    return $collection->mapToGroups(function($item, $key) {

        return ($this->isAlpha($item->name[0]) ? [strtoupper($item->name[0]) => $item] : ['#' => $item]);
    });
}

public function isAlpha($toCheck)
{
    return preg_match("/^[a-zA-Z]+$/", $toCheck);
}

Seems like an ordinary foreach() would suffice

$ordered = [];
foreach ($items as $item) {
    $key = ctype_alpha($item->attribute[0]) ? $item->attribute[0] : 'other';
    $ordered[$item->attribute[0]][] = $item;
}

The above produces an assoc array with the letter as key - and put all none-alpha items in other