I wrote the below method to list out the elements of an array, as well as adding the Oxford comma to the list if desired. However, my for-loop looks, perhaps, a little convoluted. Is there a better way to handle clearly both the Oxford comma and the ability to add a conjunction?
function listOut($array = array(), $oxford = false, $conjunction = 'and') {
$count = is_array($array) ? count($array) : 0;
switch($count) {
case 0: // Either not an array or an empty array
return '';
case 1: // Only one element in the array, return it
return $array[0];
case 2: // Two elements; join them together with the conjunction
return "{$array[0]} {$conjunction} {$array[1]}";
default: // At least two elements, join with commas and conjunction
$s = ", ";
$t = "";
for($i = 0; $i < $count; $i++) {
// Add a conjunction if it's the last element in the array
if($i + 1 === $count) {
$s = $oxford ? $s . "$conjunction " : " $conjunction ";
}
// Only prepend comma if not the first element
if($i > 0) {
$t .= $s;
}
// Add the element to the return string
$t .= $array[$i];
}
return $t;
}
}
$array1 = array('orange');
$array2 = array('white', 'gold');
$array3 = array('black', 'white', 'purple');
echo listOut($array1); // orange
echo listOut($array2); // white and gold
echo listOut($array3); // black, white and purple
echo listOut($array1, true); // orange
echo listOut($array2, true); // white and gold
echo listOut($array3, true); // black, white, and purple
1 Answer 1
You can effectively get rid of the switch statement as well as the is_array check in the count ternary if you do the check in the beginning (and exit early at that - so not wasting any cycles).
You can also get rid of
# Only prepend comma if not the first element
if($i > 0) {
$output .= $separator;
}
If you add a ternary concat to $output
(at the expense of gaining 2 opcode calls over the if/else). This would be the function after cleaning it:
function listOut($array = array(), $oxford = false, $conjunction = 'and', $separator = ", ") {
if(!is_array($array)){ # We're expecting an array
return false;
}
$count = count($array) ?: 0;
$output = "";
if($count == 2){ return implode(" $conjunction ", $array); }
for($i = 0; $i < $count; $i++) {
# Add a conjunction if it's the last element in the array
if($i + 1 === $count) {
$separator = $oxford ? $separator . "$conjunction " : " $conjunction ";
}
# Add the element to the return string
$output .= ($i > 0 ? $separator : "") . $array[$i];
}
return $output;
}
and the test outputs:
$array = 'blue';
$array1 = array('orange');
$array2 = array('white', 'gold');
$array3 = array('black', 'white', 'purple');
$array4 = array('black', 'white', 'purple', 'gold');
echo listOut($array) . "<br>";
echo listOut($array1) . "<br>"; // orange
echo listOut($array2) . "<br>"; // white and gold
echo listOut($array3, true) . "<br>"; // black, white and purple
echo listOut($array4) . "<br>"; // black, white and purple
Results:
false
orange
white and gold
black, white, and purple
black, white, purple and gold
-
\$\begingroup\$ I like a lot of the optimizations you've done! However, an Oxford comma would appear in a two-element array in this case ("white, and gold"). \$\endgroup\$Chris Forrence– Chris Forrence2014年09月30日 19:36:43 +00:00Commented Sep 30, 2014 at 19:36
-
\$\begingroup\$ Ah! Didn't test that. To solve that issue, just add
if($count == 2){ return implode(" $conjunction ", $array); }
after$count = count($array) ?: 0
. \$\endgroup\$jsanc623– jsanc6232014年09月30日 19:46:44 +00:00Commented Sep 30, 2014 at 19:46 -
\$\begingroup\$ Sounds good (and I actually made another modification to that by checking
$count <= 2
). Now I'll be able to list out items for perfectly peaceful purposes. Thank you! \$\endgroup\$Chris Forrence– Chris Forrence2014年09月30日 19:53:08 +00:00Commented Sep 30, 2014 at 19:53 -
\$\begingroup\$ Good catch on the
<=
: exit early, exit often! \$\endgroup\$jsanc623– jsanc6232014年09月30日 20:01:31 +00:00Commented Sep 30, 2014 at 20:01