--- 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