---
title: "Magic Functions to Obtain Results from for Loops in R"
author: "Koji Makiyama (@hoxo_m)"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Magic Functions to Obtain Results from for Loops in R}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.path = "README-"
)
```

## 1. Overview

`for()` is one of the most popular functions in R.
As you know, it is used to create loops.

For example, let's calculate squared values for 1 to 3.

```{r}
for (i in 1:3) {
  squared <- i ^ 2
  print(squared)
}
```

It is very easy.

However, it becomes too much hassle to change such codes to store the result.
You must prepare some containers with correct length for storing the result and change `print()` to assignment statements.

```{r}
result <- vector("numeric", 3) # prepare a container
for (i in 1:3) {
  squared <- i ^ 2
  result[i] <- squared         # change to assignment
}
result
```

Moreover, you may want to store the result as a data.frame with the iteration numbers.

```{r}
result <- data.frame(matrix(nrow = 3, ncol = 2))
colnames(result) <- c("i", "squared")
for (i in 1:3) {
  squared <- i ^ 2
  result[i, 1] <- i
  result[i, 2] <- squared
}
result
```

What a bother!

In such or more troublesome situations like that you have to store many variables, the code will grow more complex.

The **magicfor** package makes to resolve the problem being kept readability.

You just add two lines before the for loop.
First, load the library. Second, call `magic_for()`.
Notice that the main for loop is kept intact.

```{r}
library(magicfor)               # load library
magic_for(print, silent = TRUE) # call magic_for()

for (i in 1:3) {
  squared <- i ^ 2
  print(squared)
}

magic_result_as_dataframe()     # get the result
```

`magic_for()` takes a function name, and then reconstructs `for()` to remember values passed to the specified function in for loops.
We call it "magicalization".
Once you call `magic_for()`, as you just run `for()` as usual, the result will be stored in memory automatically.

Here, we are using `magic_result_as_dataframe()` in order to get the stored values.
It is one of the functions to obtain results from "magicalized for loops", and means to take out the results as a data.frame.

Even if the number of observed variables increases, you can do it the same way.

```{r}
magic_for(silent = TRUE)

for (i in 1:3) {
  squared <- i ^ 2
  cubed <- i ^ 3
  put(squared, cubed)
}

magic_result_as_dataframe()
```

`put()` is the default function to store values in magicalized for loops.
It allows to take any number of variables and can display them.

## 2. Installation

You can install the **magicfor** package from CRAN.

```{r eval=FALSE}
install.packages("magicfor")
```

The source code for **magicfor** package is available on GitHub at

- https://github.com/hoxo-m/magicfor.

## 3. Details

The **magicfor** package provides the functions as follows:

- `magic_for()`: Magicalize for.
- `magic_free()`: Free magicalization.
- Get results:
    - `magic_result()`: as a list.
    - `magic_result_as_vetor()`: as a vector.
    - `magic_result_as_dataframe()`: as a data.frame.
- `put()`: Display values.

In the following, we assume that the library is loaded to use the functions.

```{r}
library(magicfor)
```

### 3.1 Basics

The main function `magic_for()` magicalize for loops.
"Magicalize" means to change the behavior of `for()` to store values outputted via target functions.

```{r}
magic_for()

for (i in 1:3) {
  squared <- i ^ 2
  put(squared)
}
```

The default target function is `put()`. It displays input values, for example:

```{r}
x <- 1
put(x)
```

You can take out stored values using `magic_result_**()` when for loops have  finished.

```{r}
magic_result_as_vector()
```

### 3.2 `magic_for()`

`magic_for()` has several options.

Specify the first argument `func`, you can change target functions.

```{r}
magic_for(cat)

for (i in 1:3) {
  squared <- i ^ 2
  cat(squared, " ")
}
```

If `progress = TRUE`, show progress bar.

```{r eval=FALSE}
magic_for(progress = TRUE)

for (i in 1:3) {
  squared <- i ^ 2
  put(squared)
}
```

```
#> |=================================================================| 100%
```

If you set `test` a number, the iteration is limited to that number of times.

```{r}
magic_for(test = 2)

for (i in 1:100) {
  squared <- i ^ 2
  put(squared)
}
```

If `silent = TRUE`, target function will be not executed but only the values will be stored.

If `temp = TRUE`, the effect of magicalization will be lost after once execution of for loop.

```{r}
magic_for(temp = TRUE)
is_magicalized()

for (i in 1:3) {
  squared <- i ^ 2
  put(squared)
}

is_magicalized()
```

### 3.3 `magic_free()`

You can use `magic_free()` to cancel magicalization.

```{r}
magic_for()
is_magicalized()

magic_free()
is_magicalized()
```

The function also clear the stored values.

```{r}
magic_for(silent = TRUE)

for (i in 1:3) {
  squared <- i ^ 2
  put(squared)
}

magic_result_as_vector()

magic_free()
magic_result_as_vector()
```

### 3.4 `magic_result_**()`

You can use `magic_result_**()` to obtain results from magicalized for loops.

```{r}
magic_for(silent = TRUE)

for (i in 1:3) {
  squared <- i ^ 2
  put(squared)
}
```

`magic_result()` returns results as a list.

```{r}
magic_result()
```

`magic_result_as_vector()` returns results as a vector.

```{r}
magic_result_as_vector()
```

`magic_result_as_dataframe()` returns results as a data.frame.

```{r}
magic_result_as_dataframe()
```

### 3.5 `put()`

`put()` displays input values with high flexibility.

```{r}
x <- 2
y <- 3
put(x)
put(x, y)
put(x, x ^ 2, x ^ 3)
put(x, squared = x ^ 2, cubed = x ^ 3)
```

It is very useful for **magicfor**.

```{r}
magic_for()

for (i in 1:3) {
  put(x = i, squared = i ^ 2, cubed = i ^ 3)
}

magic_result_as_dataframe(F)
```

## 4. Miscellaneous

Whenever you put just variables in magicalized for loops, their values will be stored regardless of target functions.

```{r}
magic_for()

for (i in 1:3) {
  squared <- i ^ 2
  squared
}

magic_result_as_vector()
```

When you write trarget functions inside of if statements without else, `NA` will be inserted to represent missing.

```{r}
magic_for()

for (i in 1:3) {
  squared <- i ^ 2
  if(i == 3) put(squared)
}

magic_result_as_vector()
```

Target functions work only top level lines or inside of if statements in magicalized for loops.
For example, it does not work inside nested for loops.

```{r}
magic_for()

for (i in 1:2) {
  for (j in 1:2) {
    put(i, j, i * j)
  }
}

magic_result_as_vector()
```

## 5. Bug Reports

- https://github.com/hoxo-m/magicfor/issues
