---
title: "Iteration Basics"
author: "Statistical Computing, 36-350"
date: "Monday October 3, 2016"
---

Iteration
===

Computers: good at applying rigid rules over and over again. Humans: not so good at this. Iteration is at the heart of programming

Summary of methods for performing iteration in R:

- `for()`, `while()` loops
- Vectorization
- `apply()` family of functions
- `**ply()` family of functions

Reminder: conditionals and boolean operators
===

Control flow:

- `if()`, `else if()`, `else`: standard conditionals
- `ifelse()`: conditional function that vectorizes nicely
- `switch()`: handy for deciding between several options

Boolean operators:

- `&` work `|` like `+` or `*`: they combine terms elementwise
- `&&` and `||` give just a single boolean, lazily
- Standard flow flow control: we just want one boolean value. Hence we can skip calculating what's not needed

In summary, use `&&` and `||` for conditionals, `&` and `|` for indexing or subsetting

Examples of boolean operators
===

```{r}
set.seed(0)
x = runif(10, -1, 1)
x
x[0 <= x & x <= 0.5] = 999 # Elementwise AND
x

(0 > 0) && all(matrix(0,2,2) == matrix(0,3,3)) # Lazy AND
(0 > 0) && (ThisVariableIsNotDefined == 0) # Lazy AND
```

In the last two lines, R *never* evaluates the expression on the right (each of these would throw an error on its own!)

`for()` loop
===

A `for()` loop increments a **counter** variable along a vector. It repeatedly runs a code block, called the  **body** of the loop, with the counter set at its current value, until it runs through the vector

```{r}
n = 10
log.vec = vector(length=n, mode="numeric")
for (i in 1:n) {
  log.vec[i] = log(i)
}
log.vec
```

Here `i` is the counter and the vector we are iterating over is `1:n`. The body is the code in between the braces

Breaking from the loop
===

We can **break** out of a `for()` loop early (before the counter has been iterated over the whole vector), using `break`

```{r}
n = 10
log.vec = vector(length=n, mode="numeric")
for (i in 1:n) {
  if (log(i) > 2) {
    cat("I'm outta here. I don't like numbers bigger than 2\n")
    break
  }
  log.vec[i] = log(i)
}
log.vec
```

Variations on standard `for()` loops
===

Many different variations on standard `for()` are possible. Two common ones to be aware of:

- Nonnumeric counters: counter variable always gets iterated over a vector, but it doesn't have to be numeric
- Nested loops: body of the `for()` loop can contain another `for()` loop (or several others)

```{r}
for (str in c("Prof", "Ryan", "Tibs")) {
  cat(paste(str, "declined to comment\n"))
}

for (i in 1:4) {
  for (j in 1:i^2) {
    cat(paste(j,""))
  }
  cat("\n")
}
```

`while()` loop: conditional iteration
===

A `while()` loop repeatedly runs a code block, called the **body**, until some condition is no longer TRUE

```{r}
i = 1
log.vec = c()
while (log(i) <= 2) {
  log.vec = c(log.vec, log(i))
  i = i+1
}
log.vec
```

`for()` versus `while()`
===

- `for()` is better when the number of times to repeat (values to iterate over) is clear in advance

- `while()` is better when you can recognize when to stop once you're there, even if you can't guess it to begin with

- `while()` is more general, in that every `for()` could be replaced with a `while()` (but not vice versa)

`while(TRUE)` or `repeat`: unconditional iteration
===

`while(TRUE)` and `repeat`: both have the same function, just repeat the body indefinitely, until something causes the flow to break

Try running the code below in your console

```
repeat {
  ans = readline("Who is the best Professor of Statistics at CMU? ")
  if (ans == "Tibs" || ans == "Tibshirani" || ans == "Ryan") {
    cat("Yes! You get an 'A'.")
    break
  }
  else {
    cat("Wrong answer!\n")
  } 
}
```

Avoiding explicit iteration
===

Warning: some people have a tendency to **overuse** `for()` and `while()` loops in R. They aren't always needed. Useful alternatives:

- Vectorization: act on whole objects rather than iterate over individual elements. When it applies, often simpler, and faster (sometimes a little, sometimes drastically)
- `apply()` family of functions: apply a given function over dimensions of an object. E.g., elements of a vector, elements of a list, rows/columns of a matrix. Often simpler, not often faster
- `**ply()` family of functions: like `apply()` family, but much more transparent about what goes in and what comes out