Wesley Stam
Wesley Stam

Reputation: 106

Group Array Into Alphabetical

I need to render my array into a group like this:

[group]{A}
   abc
   alpha
   apple
[/group]

However, it doesn't want to work yet with this code:

sort($array, SORT_NATURAL | SORT_FLAG_CASE);
$batch = '';
$previous = strtoupper(substr($array[0], 0, 1));
foreach($array as $value) {
    $firstLetter = strtoupper(substr($value, 0, 1));

    if($previous !== $firstLetter){ 
        echo "[group]{" . substr($firstLetter, 0,1) . "}\n" . $batch . "[/group]\n\n";
        $batch = NULL;
    }
    else{
        $batch.= $value."\n";
    }

    $previous = $firstLetter;

}

Example input:

a
a
a
b
b
c

Example Output:

[submenu] (B)
a
a
a
[/group]

[submenu] (C)
b
[/group]

Output after advice from 'ElefantPhace' in the comments:

[submenu] (A)
a
a
a
[end]

[submenu] (A)
[group]

[submenu] (A)
[group]

Keeping the '$previous = $firstLetter;' after the 'else' gives me:

[submenu] (A)
a
a
a
[end]

[submenu] (B)
b
[group]

Which is fine except for the fact that I miss the last item 'c'

NOTE: I left the $previous in my group.

Upvotes: 0

Views: 683

Answers (3)

ElefantPhace
ElefantPhace

Reputation: 3814

A working example using your method:

$array = ['alpha','abc','android','braces','barbs','brackets','crabs','cool'];
sort($array, SORT_NATURAL | SORT_FLAG_CASE);
$batch = '';
$previous = strtoupper(substr($array[0], 0, 1));
$count = count($array);
$i=0;
foreach($array as $value) {
    $i++;
    $firstLetter = strtoupper(substr($value, 0, 1));
    if($previous !== $firstLetter || $i == $count){ 
        if($i == $count) $batch.=$value."\n"; 
        echo "[group]{".$previous."}\n" . $batch . "[/group]\n\n";
        $batch = $value."\n";
    }else{
        $batch.= $value."\n";
    }
    $previous = $firstLetter;
}

Output:

[group]{A} abc alpha android [/group]

[group]{B} barbs braces brackets [/group]

[group]{C} cool crabs[/group]

Not very pretty, but it works!

Upvotes: 0

Crackertastic
Crackertastic

Reputation: 4913

Working off your code you can make the following changes to get what you want:

$array = array("a", "ac", "ab", "bc", "be", "bd", "ce", "cg", "cf");

sort($array, SORT_NATURAL | SORT_FLAG_CASE);
$batch = '';
$output = '';
$previous = strtoupper(substr($array[0], 0, 1));
foreach($array as $value) {
    //Get the first letter
    $firstLetter = strtoupper(substr($value, 0, 1));
    //Check if in a new group, otherwise add $value to current group
    if($previous != $firstLetter) {
        //In a new group, so prep for the next group.
        $output .= "[group]{" . $previous . "}\n" . $batch . "[/group]\n\n";
        $previous = $firstLetter;
        $batch = '';
    } else {
        $batch .= $value."\n";
    }

}
//Get the last batch.
$output .= "[group]{" . $previous . "}\n" . $batch . "[/group]\n\n";

print($output);

This will produce:

[group]{A}
a
ab
ac
[/group]

[group]{B}
bd
be
[/group]

[group]{C}
cf
cg
[/group]

Hope that helps you out!

Upvotes: 0

Josh from Qaribou
Josh from Qaribou

Reputation: 6908

A cleaner way is to avoid the checking if you're using a new letter (the if($previous !== $firstLetter) stuff), and instead use the first letter as an index in a new array, like so:

sort($array, SORT_NATURAL | SORT_FLAG_CASE);
$treeArray = array();
foreach($array as $el) {
  $firstLetter = strtoupper(substr($el, 0, 1));
  if(!(isset($treeArray[$firstLetter])) ) { $treeArray[$firstLetter] = array(); }
  array_push($treeArray[$firstLetter], $el);
}

Now, you'll have an array which uses each of the first letters as an index, so you can loop through it later to display like:

foreach($treeArray as $letter => $contents) {
  echo '[submenu] ' . $letter, PHP_EOL;
  foreach($contents as $el) {
    echo $el, PHP_EOL;
  }
}

Upvotes: 1

Related Questions