madsynn's avatar

Trying to group my query into alphabetic chunks

Any help would be awesome.

my query so far but not sure how to connect each set of letters.

$partners = Directory::where('name', 'like', 'A%')->orderBy('name', 'asc')->get();

returns all with start letter A just fine but i want to group them into [A,B,C,D] and keeps them in that order.

I can do a query for each one but not practical so i want to output them as grouped and any help you can give would be appreciated.

my blade file loop

@foreach($partners as $letter => $group)

    <ul>

        <li>{{ $letter }}</li> // WOULD LIKE THIS TO BE " A - B - C - D "

        @foreach($group as $partner)

            <li>{{ $partner['name'] }}</li>

        @endforeach

    </ul>

@endforeach

thnx in advance

0 likes
28 replies
jlrdw's avatar

Do you want all grouped by letter or just the letter entered into a search?

bugsysha's avatar
$partners = Directory::query()->orderBy('name')->get()->groupBy(function (Directory $directory): string {
  return ($directory->name)[0];
});
@foreach($partners as $letter => $group)

    <div>{{ $letter }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

@endforeach
MichalOravec's avatar
$directories = Directory::orderBy('name')->get()->groupBy(function ($directory) {
    return strtoupper($directory->name[0]);
});
@foreach($directories as $letter => $group)
    <div>{{ $letter }}</div>

    <ul>
        @foreach($group as $directory)
            <li>
                {{ $directory->name }}
            </li>
        @endforeach
    </ul>
@endforeach

Docs: https://laravel.com/docs/8.x/collections#method-groupby

madsynn's avatar

@michaloravec and @bugsysha

Thank you for your help. I almost have what i need. Guess i should have expained better i am trying to group the letters into sections as follows and then loop through them.

The following are just arrays explaining what i am trying to do after i have queried the names. I am aware they will not work as coding i am just trying to explain what i mean.

Trying to create this. https://nimb.ws/57f2B8

Section with names starting with :

$a_though_d = [A,B,C,D];
$e_though_h = [E,F,G,H];
$i_though_l = [I,J,K,L];
$m_though_p = [M,N,O,P];
$q_though_t = [Q,R,S,T];
$u_though_x = [Y,Z];
madsynn's avatar

@jlrdw thnx;

Trying to group into groups of letters if that makes sense. Look at my new comment below I also added a screenshot. I can separate them into each letter but not sure how to group them into groups of letters.

bugsysha's avatar
$partners = Directory::query()->orderBy('name')->get()->groupBy(function (Directory $directory): string {
  $letter = $directory->name[0];
  return in_array($letter, range('A', 'Z')) ? $letter : 'Other';
})->chunk(4);
@foreach($partners as $letter => $group)

    <div>{{ $letter }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

@endforeach
MichalOravec's avatar

Yeah chunk will work.

$directories = Directory::orderBy('name')->get()->groupBy(function ($directory) {
    return strtoupper($directory->name[0]);
});
@foreach ($directories->chunk(4) as $chunk)
    @foreach($chunk as $letter => $group)
        <div>{{ $letter }}</div>

        <ul>
            @foreach($group as $directory)
                <li>
                    {{ $directory->name }}
                </li>
            @endforeach
        </ul>
    @endforeach
@endforeach

Docs: https://laravel.com/docs/8.x/collections#method-chunk

madsynn's avatar

@bugsysha

Thank you that is right along the lines i need but with couple new questions.

Here is my output when I run it with DD.

https://nimb.ws/kL70Ez

When I try to output to the view i get an error saying name is not part of the collection but it clearly is.

Next question is there a way to make the "OTHER" last in the output so each group follows the earlier screenshot.

Thank you by the way you rock.

madsynn's avatar

@michaloravec Thank you but still not quite what i am looking for. Its almost there.

This is a dump of what you sent me. https://nimb.ws/bnNwQ0

It looks like the loop is just grabbing the first letter and grouping them into the letter they start with and no other data. When i output the loop it says not name on this collection. Same problem i keep running into. so the output to the blade file errors out.

Thank you so much for helping me tackle this.

bugsysha's avatar
$partners = Directory::query()->orderBy('name')->get()->groupBy(function (Directory $directory): string {
  $letter = $directory->name[0];
  return in_array($letter, range('A', 'Z')) ? $letter : 'Other';
})->sortBy(function (string $text, string $key):int {
  return collect(range('A', 'Z'))->flip()->get($key, 100);
})->chunk(4);
@foreach($partners as $letter => $group)

    <div>{{ $letter }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

@endforeach
bugsysha's avatar

@madsynn also please fully expand one collection and post a screenshot, let's say A just to see what is the contents so I can answer that other question where no name on the collection.

1 like
bugsysha's avatar

I've forgot about chunking.

@foreach($partners as $partnerChunk)

  @foreach($partnerChunk as $letter => $group)

    <div>{{ $letter }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

  @endforeach

@endforeach
MichalOravec's avatar

You got that result because I used chunk in the foreach loop.

madsynn's avatar

@bugsysha

Almost have it. it is outputting to blade now but its outputting per letter not per group.

A
 AbeT 
 Agilant
 Alde 
 Allscript 
 AM Mobile
 Appetize
 Appogee
 Arlington 
 Atlanta Computer 

B
 Bar   Unlimited
 Barcodes Inc.
 Biz  POS
 Brad  Incorporated

The chunk in the foreach was what was grouping them correctly though wasn't it.

Now how do I group them together without it?

bugsysha's avatar

@madsynn I'm not sure what is not correct at this moment. Show me an example what you want to output.

bugsysha's avatar

@madsynn maybe I do get it.

@foreach($partners as $partnerChunk)

  @foreach($partnerChunk as $group)

    <div>{{ $partnerChunk->keys()->implode(' - ') }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

  @endforeach

@endforeach
madsynn's avatar

@bugsysha

Thank you so much for helping me tackle this.

Once they are grouped and outputing how do o loop through each group so i can style them differently?

Each section is in its own container and styled a little differently.

bugsysha's avatar
bugsysha
Best Answer
Level 61
@foreach($partners as $partnerChunk)

  @foreach($partnerChunk as $group)

    <div class="{{ $partnerChunk->keys()->implode('') }}">{{ $partnerChunk->keys()->implode(' - ') }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

  @endforeach

@endforeach
.ABCD { background: red; }
.EFGH { background: black; }
bugsysha's avatar
@foreach($partners as $partnerChunk)

  @foreach($partnerChunk as $group)

@if ($loop->first)
    <div class="{{ $partnerChunk->keys()->implode('') }}">{{ $partnerChunk->keys()->implode(' - ') }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "
@endif

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

  @endforeach

@endforeach
1 like
madsynn's avatar

@bugsysha

Thank you very much. You really made that look easy and I appreciate the help. Its not like the stuff I code normally and appreciate it very much.

You totally rock!

bugsysha's avatar

You are very welcome. Thank you for the Best Reply award.

jlrdw's avatar

I know you amost have it, but I would use

GROUP BY substr(your_field, 1, 1)
ORDER BY your_field ASC   // 

But write query where first round less than e

second round greater than d less than i

etc.

You can work out your counter.

But I usually don't use eloquent, I usually use getPdo() and write regular queries.

madsynn's avatar

@bugsysha

I was wondering if i could get your help one more time. This works great but i need one more adjustment if you could help please.

@foreach($partners as $partnerChunk)

  @foreach($partnerChunk as $group)

@if ($loop->first)
    <div class="{{ $partnerChunk->keys()->implode('') }}">{{ $partnerChunk->keys()->implode(' - ') }}</div> // WOULD LIKE THIS TO BE " A - B - C - D "
@endif

    <ul>

        @foreach($group as $partner)

            <li>{{ $partner->name }}</li>

        @endforeach

    </ul>

  @endforeach

@endforeach

This outputs correctly but in one big list. I need it to do tow sections at a time for a total of 4 columns.

Can you help me get the code right. thank you.

bugsysha's avatar

Not sure I understand two sections at a time for a total of 4 columns, but you need to use CSS for that. I use TailwindCSS so for me that would be something like <div class="grid grid-cols-4"> columns here </div>.

Please or to participate in this conversation.