You are on page 1of 9

Unit 2: Control structures: If Statements, else Statements, if-else statement,

Nesting and Stacking Statements, The switch statement,


Control structures

if Statements

The if statement is the key to controlling exactly which operations are carried
out in a given chunk of code. An if statement runs a block of code only if a
certain condition is true. These constructs allow a program to respond
differently depending on whether a condition is TRUE or FALSE.

if(condition){
do any code here
}

The condition is placed in parentheses after the if keyword. This condition must
be an expression that yields a single logical value (TRUE or FALSE). If it’s
TRUE, the code in the braces, {}, will be executed. If the condition isn’t
satisfied, the code in the braces is skipped, and R does nothing (or continues on
to execute any code after the closing brace).
Here’s a simple example. In the console, store the following:

R> a <- 3
R> mynumber <- 4

Now, in the R editor, write the following code chunk:

if(a<=mynumber){
a <- a^2
}

When this chunk is executed, what will the value of a be? It depends on the
condition defining the if statement, as well as what’s actually specified in the
braced area. In this case, when the condition a<=mynumber is evaluated, the
result is TRUE since 3 is indeed less than or equal to 4. That means the code
inside the braces is executed, which sets a to a^2, or 9.
else Statements
The if statement executes a chunk of code if and only if a defined condition is
TRUE. If you want something different to happen when the condition is
FALSE, you can add an else declaration. Here’s an example in pseudocode:

if(condition){
do any code in here if condition is TRUE
} else {
do any code in here if condition is FALSE
}

You set the condition, then in the first set of braces you place the code to run
if the condition is TRUE. After this, you declare else followed by a new set of
braces where you can place code to run if the condition is FALSE.

R> a <- 3
R> mynumber <- 4

In the editor, create a new version of the earlier if statement.

if(a<=mynumber){
cat("Condition was",a<=mynumber)
a <- a^2
} else {
cat("Condition was",a<=mynumber)
a <- a-3.5
}
a

Here, you again square a if the condition a<=mynumber is TRUE, but if FALSE,
a is overwritten by the result of itself minus 3.5. You also print text to the console
stating whether the condition was met. After resetting a and mynumber to their
original values, the first run of the if loop computes a as 9, just as earlier,
outputting the following:

Condition was TRUE


R> a
[1] 9

Now, immediately highlight and execute the entire statement again. This
time around, a<=mynumber will evaluate to FALSE and execute the code
after else.

Condition was FALSE


R> a
[1] 5.5

Nesting and Stacking Statements


An if statement can itself be placed within the outcome of another if statement.
By nesting or stacking several statements, you can weave intricate paths of
decision-making by checking a number of conditions at various stages during
execution.
In the editor, modify the mynumber example once more as follows:

if(a<=mynumber){
cat("First condition was TRUE\n")
a <- a^2
if(mynumber>3){
cat("Second condition was TRUE")
b <- seq(1,a,length=mynumber)
} else {
cat("Second condition was FALSE")
b <- a*mynumber
}
} else {
cat("First condition was FALSE\n")
a <- a-3.5
if(mynumber>=4){
cat("Second condition was TRUE")
b <- a^(3-mynumber)
} else {
cat("Second condition was FALSE")
b <- rep(a+mynumber,times=3)

}
}
a
b

Here you see the same initial decision being made as earlier. The value a is
squared if it’s less than or equal to mynumber; if not, it has 3.5 subtracted from
it. But now there’s another if statement within each braced area. If the first
condition is satisfied and a is squared, you then check whether mynumber is
greater than 3. If TRUE, b is assigned seq(1,a,length=mynumber). If FALSE, b
is assigned a*mynumber.
If the first condition fails and you subtract 3:5 from a, then you check a second
condition to see whether mynumber is greater than or equal to 4. If it is, then b
becomes a^(3-mynumber). If it’s not, b becomes rep(a+mynumber,times=3).
Note that I’ve indented the code within each subsequent braced area to make it
easier to see which lines are relevant to each possible decision.
Now, reset a <- 3 and mynumber <- 4 either directly in the console or from the
editor. When you run the mynumber example code, you’ll get the following
output:

First condition was TRUE


Second condition was TRUE
R> a
9
R> b
1.000000 3.666667 6.333333 9.000000
The result indicates exactly which code was invoked—the first condition and
second condition were both TRUE. Trying another run of the same code, after
first setting

R> a <- 6
R> mynumber <- 4

you see this output:

First condition was FALSE


Second condition was TRUE
R> a
2.5
R> b
0.4

This time the first condition fails, but the second condition checked inside
the else statement is TRUE.
Alternatively, you could accomplish the same thing by sequentially stacking if
statements and using a combination of logical expressions in each condition. In
the following example, you check for the same four situations, but this time you
stack if statements by placing a new if declaration immediately following an
else declaration:

if(a<=mynumber && mynumber>3){


cat("Same as 'first condition TRUE and second TRUE'")
a <- a^2
b <- seq(1,a,length=mynumber)
} else if(a<=mynumber && mynumber<=3){
cat("Same as 'first condition TRUE and second FALSE'")
a <- a^2
<- a*mynumber
} else if(mynumber>=4){
cat("Same as 'first condition FALSE and second TRUE'")
a <- a-3.5
b <- a^(3-mynumber)
} else {
cat("Same as 'first condition FALSE and second FALSE'")
a <- a-3.5
b <- rep(a+mynumber,times=3)
}
a
b

Just as before, only one of the four braced areas will end up being executed.
Comparing this to the nested version, the first two braced areas correspond to
what was originally the first condition (a<=mynumber) being satisfied, but this
time you use && to check two expressions at once. If neither of those two
situations is met, this means the first condition is false, so in the third statement,
you just have to check whether mynumber>=4. For the final else statement, you
don’t need to check any conditions because that statement will be executed only
if all the previous conditions were not met.
If you again reset a and mynumber to 3 and 4, respectively, and execute the
stacked statements shown earlier, you get the following result:

Same as 'first condition TRUE and second TRUE'


R> a
9
R> b
1.000000 3.666667 6.333333 9.000000

This produces the same values for a and b as earlier. If you execute the code
again using the second set of initial values (a as 6 and mynumber as 4), you get
the following:

Same as 'first condition FALSE and second TRUE'


R> a
[1] 2.5
R> b
[1] 0.4

This again matches the results of using the nested version of the code.

The switch Function


Let’s say you need to choose which code to run based on the value of a single
object. One option is to use a series of if statements, where you compare the
object with various possible values to produce a logical value for each
condition. Here’s an example:

if(mystring=="Homer"){foo <- 12}


else if(mystring=="Marge"){ foo <- 34}
else if(mystring=="Bart"){ foo <- 56}
else if(mystring=="Lisa"){ foo <- 78}
else if(mystring=="Maggie"){ foo <- 90}
else {foo <- NA}

The goal of this code is simply to assign a numeric value to an object foo, where
the exact number depends on the value of mystring. The mystring object can
take one of the five possibilities shown, or if mystring doesn’t match any of
these,
‘;p foo is assigned NA.
R> mystring <- "Lisa"

and executing the chunk, you’ll see this:

R> foo
[1] 78

Setting the following

R> mystring <- "Peter"

and executing the chunk again, you’ll see this:


R> foo
[1] NA

This setup using if-else statements is quite cumbersome for such a basic
operation, though. R can handle this type of multiple-choice decision in a far
more compact form via the switch function. For example, you could rewrite the
stacked if statements as a much shorter switch statement as follows:

R> mystring <- "Lisa"


R>foo<-
switch(EXPR=mystring,Homer=12,Marge=34,Bart=56,Lisa=78
,Maggie=90,NA)
R> foo
[1] 78

and

R> mystring <- "Peter"


R> foo <-
switch(EXPR=mystring,Homer=12,Marge=34,Bart=56,Lisa=78
,Maggie=90,NA)
R> foo
[1] NA

The first argument, EXPR, is the object of interest and can be either a numeric
or a character string. The remaining arguments provide the values or operations
to carry out based on the value of EXPR. If EXPR is a string, these argument
tags must exactly match the possible results of EXPR. Here, the switch statement
evaluates to 12 if mystring is "Homer", 34 if mystring is "Marge", and so on.
The final, untagged value, NA, indicates the result if mystring doesn’t match any
of the preceding items.
The integer version of switch works in a slightly different way. Instead of
using tags, the outcome is determined purely with positional matching.
Consider the following example:
R> mynum <- 3
R> foo <- switch(mynum,12,34,56,78,NA)
R> foo
[1] 56

Here, you provide an integer mynum as the first argument, and it’s positionally
matched to EXPR. The example code then shows five untagged arguments: 12
to NA. The switch function simply returns the value in the specific position
requested by mynum. Since mynum is 3, the statement assigns 56 to foo. Had
mynum been 1, 2, 4, or 5, foo would’ve been assigned 12, 34, 78, or NA,
respectively. Any other value of mynum (less than 1 or greater than 5) will
return NULL.

R> mynum <- 0


R> foo <- switch(mynum,12,34,56,78,NA)
R> foo
NULL

You might also like