# For every fruit there is a loop ... i.e., more on control flow

25 Feb 2022This week’s problem set and extra-credit opportunity can be found here:

The big new concept or construct discussed this week was the for-loop. Similar to the `if`

and `else`

constructs, the for-loop allows us to control the flow of operations in R. Whereas the `if`

and `else`

construct allows us to get the computer to do one thing ** if** some condition is

`TRUE`

and another thing **the condition is**

*if*`FALSE`

, the for-loop construct allows us to instruct the computer to repeat a task or calculation as set number of times. This works like so:```
# define object.o as a sequence of integers
object.o <- 1:10
for (element.i in object.o) {
# do something like say
print("Hello") # or
print(element.i) # or
Sys.sleep(time = 2) # go to sleep for 2 seconds
}
```

The above code will instruct the computer to repeat the tasks of printing `"Hello"`

, printing an `element.i`

from the `object.o`

, and sleeping for 2 seconds, 10 times each.

We can use these for-loop constructs for all sorts of tasks that need to be repeated a certain number of times. Say, I need 10 random numbers. We could do the following:

```
rnorm(n = 10, mean = 0, sd = 1) # returns 10 random numbers
# as one vector.
```

Or we could instruct R to give us 1 random number 10 times in a row.

```
for (i in 1:10) {
x <- rnorm(n = 1, mean = 0, sd = 1)
print(x)
}
```

If we ask R to do something once for every element `i`

in a sequence of integers say `1:10`

, we can use the fact that the `i`

’s are integers to index vectors and store output in specific locations of some vector. This might look something like this.

```
x <- rep(NA, times = 10) # initiate an empty vector
for (i in 1:10) {
x[i] <- sample(x = letters, size = 1, replace = TRUE)
}
```

In the above code we asked R to pick one random letter from the alphabet (the object `letters`

) and store the random letter in the `i`

th location of the empty `NA`

vector `x`

. At the end of the loop the vector `x`

will contain 10 random letters.

Another use for loops might be the creation of counters (in combination with `if`

and `else`

constructs).

Suppose we wanted to count the number of even numbers in some vector of integers. A for-loop can help solve this problem.

```
random.integers <- sample(x = 1:1000, size = 100, replace = TRUE)
# initiate two counters and set them to zero
even.counter <- 0
odd.counter <- 0
for (i in 1:100) {
if (random.integers[i] %% 2 == 0) {
even.counter <- even.counter + 1
} else {
odd.counter <- odd.counter + 1
}
}
even.counter
odd.counter
```

During class on Tuesday we also reviewed the creation of functions by way of revisiting Problem Set 4. A set of possible responses is reproduced below.

Consider two examples:

#### The min

```
my_min <- function(input) {
output <- sort(x = input, decreasing = FALSE)
return(output)
}
# test my_min() and compare to min()
x <- 10:1
y <- c(0, 1, -1)
z <- rnorm(n = 10, mean = 0, sd = 1)
min(x= x)
min(x= y)
min(x= z)
my_min(input = x)
my_min(input = y)
my_min(input = z)
```

#### The mean

```
my_mean <- function(input) {
ouput <- sum(x = input)/length(x = input)
return(output)
}
```

#### Even vs. odd

```
even <- function(input) {
output <- ifelse(test = input %% 2 == 0,
yes = "even",
no = "odd")
return(output)
}
```

#### Absolute value (Version 1)

```
my_abs <- function(input) {
output <- ifelse(test = input < 0,
yes = input * -1,
no = input)
return(output)
}
```

#### Absolute value (Version 2)

```
my_abs <- function(input) {
output <- sqrt(x = input^2)
return(output)
}
```

#### Median

```
# this version depends on the even() function above
my_median <- function(input) {
n <- length(x = input)
x <- sort(x = input)
if (even(input = n) == "even") {
return(mean(x = x[n/2, n/2 + 1]))
} else {
return(x[ceiling(x = n/2)])
}
}
# test my_median() on even and odd length inputs
# and compare to median()
x <- rnorm(n = 100)
y <- rnorm(n = 101)
median(x = x)
my_median(input = x)
median(x = y)
my_median(input = y)
```

On Tuesday, we also covered a number other control flow operators (`repeat`

and `while`

-loops) and a few odd functions. See examples below:

#### all( ), any( ), and is.element( )

```
x <- -5:5
# Query if all elements of the vector x contain values smaller than 0
all(x < 0)
# Query if any elements of the vector x contain values smaller than 0
any(x < 0)
# Eveluates if elements of the first vector (A and B) and elements of
# the second vector (A ... Z). They of course are and the function
# will return TRUE, TRUE as both A and B are part of the vector of
# all letters in the alphabet
is.element(c("A", "B"), LETTERS)
# The is.element function is equivalent to the %in% operator
# The below will evaluate if the values in the sequence from
# 0 to 3 can be found in the sequence from 1:10. The command
# will obviously return FALSE, TRUE, TRUE, and TRUE.
0:3 %in% 1:10
```

#### counters

In the code below a counter is initiated at zero and then updated in the for-loop if an element of x is even.

```
x <- c(2, 5, 3, 9, 8, 11, 6)
count <- 0
for (i in 1:length(x)) {
if(x[i] %% 2 == 0) {
count <- count + 1
}
}
count
```

#### repeat-loop with the ‘break’ control flow operator

A repeat-loop will continue forever unless you specify a **break**.

```
x <- 1
repeat {
print(x)
x <- x + 1
if (x == 6) {
break
}
}
```

#### for-loop with ‘next’ control flow operator

I forgot to mention this operator in class. Its usage and purpose is fairly straightforward. The **next** operator basically instructs R to skip back to the beginning of the loop i.e., it is a temporary **break**.

```
for (i in 1:5) {
if (i == 3) {
next
}
print(i)
}
```

#### while-loop with counter

The while loop repeats commands *while* some condition is met. As long as the condition is true the loop will continue. Make sure that the condition can be broken else the while-loop will continue, forever-ever.

```
count <- 0
while (count < 6) {
print(count)
count <- count + 1
}
```