5
\$\begingroup\$

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
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

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
\$\endgroup\$
4
  • \$\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\$ 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
    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\$ Sep 30, 2014 at 19:53
  • \$\begingroup\$ Good catch on the <=: exit early, exit often! \$\endgroup\$
    – jsanc623
    Sep 30, 2014 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.