# 9 Control Flow

So far, all of the code we’ve written contained a sequence of R expressions that were to be evaluated in order. While this type of code can still be useful, by introducing **control flow**^{1}, we can use code to more interestingly define when and how many times various expressions should be evaluated.

After reading this chapter you should be able to:

*Use*`if`

and`else`

statements to conditionally evaluate R expressions.*Use*`ifelse`

as a vectorized alternative to`if`

and`else`

statements.

## 9.1 `if`

First, for documentation on control flow in R, use:

`::Control ?base`

We’ll start with the simplest and most important control flow constructs, the `if`

statement, which allows for conditional evaluation of R expressions. The general syntax is given by:

```
if (condition) {
code_to_evaluate }
```

First, note that `if`

is *not* a function, and we place a space between `if`

and the `(`

that follows to make this clear. Inside those parentheses, the `condition`

determines whether or not to evaluate `code_to_evaluate`

. In particular, `condition`

must be an R expression that evaluates to a length one logical vector containing either TRUE or FALSE. Much like functions, the “body” of the `if`

statement is contained within curly braces, `{}`

. This is not strictly necessary, and can be avoided for one-line statements, but we recommend that beginners always use the braces to clarify exactly which expressions will be conditionally evaluated.^{2}

```
if (TRUE) {
print("Hello, World!") # evaluates because condition is TRUE
}
```

`#> [1] "Hello, World!"`

```
if (FALSE) {
print("Hello, World!") # does not evaluate because condition is TRUE
}
```

Obviously, using `TRUE`

or `FALSE`

for the input to the condition is not particularly useful. Instead, using code the evaluates to `TRUE`

or `FALSE`

will be much more common.

```
= "bar"
foo if (is.character(foo)) {
print(foo)
}
```

`#> [1] "bar"`

```
= 42
baz if (is.character(baz)) {
print(baz)
}
```

Note that if the condition is not a logical value, R will attempt to coerce it to be logical.

```
if (42) {
print("Hello, World!")
}
```

`#> [1] "Hello, World!"`

As we’ve seen previously, sometimes this is not possible.

```
if ("foo") {
print("Hello, World!")
}
```

`#> Error in if ("foo") {: argument is not interpretable as logical`

Be aware that the condition *must* be length one. Conditions greater than length one will result in an error.

```
if (c(TRUE, FALSE)) {
42
}
```

`#> Error in if (c(TRUE, FALSE)) {: the condition has length > 1`

## 9.2 `else`

Consider the following code:

```
= 42
x if (x > 100) {
print("x is greater than 100")
}if (x <= 100) {
print("x is less than or equal to 100")
}
```

`#> [1] "x is less than or equal to 100"`

This is valid code, however, it might not be the best way to write it. We can improve this code by adding an `else`

statement.

```
= 42
x if (x > 100) {
print("x is greater than 100")
else {
} print("x is less than or equal to 100")
}
```

`#> [1] "x is less than or equal to 100"`

You’ll probably first notice that this code looks similar to the previous code. The benefit to using `else`

here is that we do no need to determine what the complement of `x > 100`

is, to ensure that the body of only one of the `if`

statements is run. In this case it is obvious, but in more complex situations, determine the complement expression could be non-trivial.

While `if`

can be used without `else`

, an `else`

usage must follow an `if`

usage. The general syntax is:

```
if (condition) {
# run this code if the condition evaluates to TRUE
else {
} # run this code if the condition evaluates to FALSE
}
```

It is also possible to chain together multiple `if`

and `else`

statements.

```
# setup data
= 22
m = 0
n
# series of if-else statements
if (m < 20) {
= 20 # will run if m < 20
n else if (m < 40) {
} = 40 # will run if 20 <= m < 40
n else if (m < 60) {
} = 60 # will run if 40 <= m < 60
n else {
} = Inf # will run if 60 <= m
n
}
# check "result"
n
```

`#> [1] 40`

One “trick” to be aware of, R will evaluate the code in the body of the **first** condition met. For example `22 < 40`

and `22 < 60`

will both evaluate to `TRUE`

, but `22 < 40`

occurs first, thus `n = 40`

is evaluated, and the remainder to the chain is ignored.

## 9.3 `ifelse`

Knowing that R is extremely vector-focused, `if`

statements might feel like a bit of an outlier given that the condition must evaluate to a *single* `TRUE`

or `FALSE`

value, that is, a logical vector of length one.

Thankfully, R includes the `ifelse`

function, which can be thought of as a “vectorized” version of the usual `if`

and `else`

construction. For details, use:

`::ifelse ?base`

First let’s translate the following `if`

and `else`

code to an `ifelse`

usage.

```
if (42 > 2) {
"!"
else {
} "?"
}
```

`#> [1] "!"`

`ifelse(test = 42 > 2, yes = "!", no = "?")`

`#> [1] "!"`

Simple enough, but that was a terribly boring example, because `42 > 2`

evaluates to `TRUE`

, and thus is a logical vector of length one. The following example will better demonstrate the power of the `ifelse`

function.

`ifelse(1:10 %% 2 == 0, "even", "odd")`

`#> [1] "odd" "even" "odd" "even" "odd" "even" "odd" "even" "odd" "even"`

First, note that we are not using the argument names in this example, as often, that will be how you see `ifelse`

examples presented.

Next, let’s look at the result of evaluating the value passed to the `test`

argument.

`1:10 %% 2 == 0`

`#> [1] FALSE TRUE FALSE TRUE FALSE TRUE FALSE TRUE FALSE TRUE`

So, it *appears* that the `ifelse`

function takes as input a logical vector, potentially of length greater than one, and returns a vector with the `yes`

argument’s value (`"even"`

) in place of any `TRUE`

values, and the `no`

argument’s value (`"odd"`

) in place of any `FALSE`

value.

Hopefully, you’re already yelling: “But there is actually vector recycling taking place!”

R will recycle the `yes`

and `no`

inputs to have the same length as the `test`

. If either of `yes`

or `no`

is longer than `test`

, any element at an index beyond the length of `test`

is ignored.

Use what you’ve already learned about recycling to reason through the following example.

```
= c(TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE)
test_ex = c(0, 1)
yes_ex = c(2, 4, 6)
no_ex ifelse(test_ex, yes_ex, no_ex)
```

`#> [1] 0 4 0 1 4 6 0 1`

## 9.4 Loops

Loops (`for`

, `while`

, and `repeat`

) are another form of control flow. We will put off discussing these until next chapter so that we can first introduce the apply functions as a more common R approach to performing the types of operations usually done in other languages with loops.

## 9.5 Summary

- TODO: You’ve learned to…

## 9.6 What’s Next?

- TODO: iteration

## 9.7 TODO

- TODO: see also: Hands-On Programming with R: else Statements
- TODO: we used print here a lot, that doesn’t mean that you should.
- TODO:
`switch`

Control flow is a defining characteristic of imperative programming.↩︎

This will also be benefical when we also add

`else`

statements.↩︎