Handling ranges with switch in PHP

Conditional code exection is one of the most important features in programming languages. Therefore most, not to say all, languages provide the if construct.

If there are many conditions you can of course use as many if statements but for this case the switch construct is what you’re looking for, which is shown in the first code example.

switch($number)
{
    case 0:
        /* do something when $number is 0 */
        break;

    case 3:
    case 4:
    case 5:
        /* do something when $number is between 3 and 5 */
        break;

    default:
        /* execute this if no other condition matches */
}

In the first line the switch construct is passed a variable and all the cases then specify what code should be executed depending on the value of $number.

To check if a number is in a certain range you can chain cases as shown for the values 3-5. For small numbers the chaining technique is fine but the bigger the number is the more uncomfortable it becomes to write down all the cases.

To minimize the effort, in PHP but maybe in other languages too, you can define conditions for the cases instead of bare numbers. So the first you probably would do is rewriting the above code to something which looks like the next example.

Note: for the people in a hurry, don’t use this example but the last one in this article.

$amount = 53;
for( $i=0 ; $i < $amount ; $i++)
{    
    switch($i)
    {
        // 1st column
        case $i < ( $amount % 3 + floor($amount / 3) * 1):
            
            $col1 .= "$i:";
            break;
        
        // 2nd column
        case $i < ($amount % 3 + floor($amount / 3) * 2):
            
            $col2 .= "$i:";
            break;
        
        // 3rd column
        case $i <= ($amount % 3 + floor($amount / 3) * 3):
            
            $col3 .= "$i:";
            break;
        
        // this should never happen
        default:
            break;
    }
}

The above snippet essentially looks if a number is in one of three ranges. The exact purpose of these ranges was to split the elements of an array into three more or less equivalent big portions to be rendered as three seperate lists.

Note: The % character is the modulo operator which returns you the rest of a integer division. As 53 cannot be divided into three totally equivalent parts, here 53 is divided into three parts of 17 elements each while the rest of two elements (53 minus 3x17) are assigned the first portion.

The following figure shows an example of a three-column list which, in HTML, is made out of three separate lists using the ul and li tags.

three_columns_list

We are on the right track, the code still has a bug though. We'll notice this when we output the variables $col1, $col2 and $col3.

echo "$col1 <br> $col2 <br> $col3";

We expect three portions of numbers with all their amounts alltogether being 53. However the output shows only 52 elements.

1:2:3:4:5:6:7:8:9:10:11:12:13:14:15:16:17:18:
19:20:21:22:23:24:25:26:27:28:29:30:31:32:33:34:35:
36:37:38:39:40:41:42:43:44:45:46:47:48:49:50:51:52:

The for loop ran from 0 to 52 so the very first element has unexpectedly disappeared in spite of the condition 0 < 19.

The reason for this is stupid simple but not necessarily trivial to detect.

If you assume a case being executed if its condition holds true then you have to reconsider how the switch construct works. To remember, the condition of the first case looked as follows.

$i < ( $amount % 3 + floor($amount / 3) * 1)

After partly computation the condition corresponds to the next mathematical expression.

0 < ( 2 + 17 )

This holds true but the switch construct doesn't stop its computation at this point. The result of the condition will be finally compared with the $number's value.

$i == ( $i < ( $amount % 3 + floor($amount / 3) * 1) )

After the computation of the right side the switch construct will compare both values, zero on the left and one on the right.

0 == 1

This will definitely be evaluated to false.

To make the above snippet work just replace switch($i) with switch(true).

$amount = 53;
for( $i=0 ; $i < $amount ; $i++)
{    
    switch(true)
    {
        // 1st column
        case $i < ( $amount % 3 + floor($amount / 3) * 1):
            
            $col1 .= "$i:";
            break;
        
        // 2nd column
        case $i < ($amount % 3 + floor($amount / 3) * 2):
            
            $col2 .= "$i:";
            break;
        
        // 3rd column
        case $i <= ($amount % 3 + floor($amount / 3) * 3):
            
            $col3 .= "$i:";
            break;
        
        // this should never happen
        default:
            break;
    }
}

1 Comment

  1. Appreciation to my father who stated to me concerning this blog, this web site is really amazing.

    Stop by my web-site: different yoga (Lourdes)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>