While I always look for the clever calculated process for handling a task like this, I'll offer a much more pedestrian alternative. (For the record, I hate writing a battery of if-elseif-else
conditions almost as much as I hate the verbosity of a switch-case
block.) For this narrow task, I am electing to abandon my favored array functions and conditionally print the values with their customized delimiters.
While this solution is probably least scalable on the page, it is likely to be the easiest to comprehend (relate the code to its generated output). If this is about "likes" or something, I don't really see a large demand for scalability -- but I could be wrong.
Pay close attention to the 2-count case. My solution delimits the elements with and
instead of ,
which seems more English/human appropriate.
Code: (Demo)
$arrays[] = array();
$arrays[] = array('user1');
$arrays[] = array('user1', 'user2');
$arrays[] = array('user1', 'user2', 'user3');
$arrays[] = array('user1', 'user2', 'user3', 'user4');
$arrays[] = array('user1', 'user2', 'user3', 'user4', 'user5');
foreach ($arrays as $i => $array) {
echo "TEST $i: ";
if (!$count = sizeof($array)) {
echo "nobody";
} elseif ($count == 1) {
echo $array[0];
} elseif ($count == 2) {
echo "{$array[0]} and {$array[1]}";
} elseif ($count == 3) {
echo "{$array[0]}, {$array[1]}, and {$array[2]}";
} else {
echo "{$array[0]}, {$array[1]}, {$array[2]}, and " , $count - 3, " other" , ($count != 4 ? 's' : '');
}
echo "\n---\n";
}
Output:
TEST 0: nobody
---
TEST 1: user1
---
TEST 2: user1 and user2
---
TEST 3: user1, user2, and user3
---
TEST 4: user1, user2, user3, and 1 other
---
TEST 5: user1, user2, user3, and 2 others
---
p.s. A more compact version of the same handling:
Code: (Demo)
if (!$count = sizeof($array)) {
echo "nobody";
} elseif ($count < 3) {
echo implode(' and ', $array);
} else{
echo "{$array[0]}, {$array[1]}";
if ($count == 3) {
echo ", and {$array[2]}";
} else {
echo ", {$array[2]}, and " , $count - 3, " other" , ($count != 4 ? 's' : '');
}
}
And finally, here's an approach that "doctors up" the array and prepends and
to the final element. I think anyway you spin this task, there's going to be a degree of convolution.
Code: (Demo)
$count = sizeof($array);
if ($count < 3) {
echo implode(' and ', $array);
} else {
if ($count == 3) {
$array[2] = "and {$array[2]}";
} else {
$more = $count - 3;
array_splice($array, 3, $more, ["and $more other" . ($more > 1 ? 's' : '')]);
}
echo implode(', ', $array);
}
During a CodeReview, I realized a "pop-prepend-push" technique: https://codereview.stackexchange.com/a/255554/141885
From PHP8, match()
is also available. An implementation might look like this: (Demo)
$count = count($array);
echo match ($count) {
0 => 'nobody',
1 => $array[0],
2 => implode(' and ', $array),
3 => "{$array[0]}, {$array[1]}, and {$array[2]}",
default => "{$array[0]}, {$array[1]}, {$array[2]}, and " . $count - 3 . " other" . ($count != 4 ? 's' : '')
};