Loops in R

Last updated on

October 25, 2024

Abstract

Looping is the repeated evaluation of a statement or block of statements.

What is a loop (in R)?

Looping is the repeated evaluation of a statement or block of statements. Base R provides functions for explicit (i.e., for, while, repeat) and implicit looping (e.g., apply, sapply, lapply,…). There are also other packages (e.g., parallel, purrr, furrr) that offer more advanced or parallelized looping capabilities, providing more efficient and convenient ways to iterate over data, particularly for complex workflows or large datasets.

lapply

We begin by using the lapply function that applies a function over a list or vector. The function needs 2 arguments as inputs:

  • X: a vector (atomic or list)
  • FUN: the function to be applied to each element of X

lapply returns a list of the same length as the input X (see ?lapply).

Two (nearly equivalent) examples with lapply:

printList1 <- lapply(X = 1:3,
                     FUN = print) 
[1] 1
[1] 2
[1] 3
printList2 <-  lapply(X = 1:3,
1                      FUN = function(x) {
2                        ret <- x^2 |>
                                print()
                        return(ret) 
                       }
                    ) 
1
Defines an so-called anonymous function that takes an argument x.
2
This approach offers further customization of operations such as calculating the square of x (for more see Functions in R).
[1] 1
[1] 4
[1] 9
Use your own function with apply family.

If the function() becomes more complex, it might be better to define it separately (and save in your src folder, see the section on Structure and Create the Project Folder(s)).

Example: Calculating many scale scores

In this example, we calculate many scale scores by using a named list and the sapply function. sapply is a user-friendly version and wrapper of lapply by default returning a vector, matrix or, if simplify = "array", an array […].

Code
calcScaleScore <- function( data,
                            items,
                            score = "sum" ) {

  validItems <- items %in% colnames(data)
  
  missingItems <- items[!validItems]
  
  if (length(missingItems) > 0) {

      stop("The following item(s) is/are not in the dataset: ",
           paste(missingItems, collapse = ", "))

    }

  if (score == "sum") {

    ret <- rowSums(data[,items])

  } else if ( score == "mean" ) {

    ret <- rowMeans(data[,items])

  } else {

    stop("score argument must be either 'sum' or 'mean'")

  }

  return(ret)

}
  • A simulated data set (wideLSdat) that can be found in the Example Data section.
  • a named list (wideLSVar).
Code
wideLSVar <- list("Y1" = paste0("Y", 1:3, 1),
                  "Y2" = paste0("Y", 1:3, 2),
                  "Y3" = paste0("Y", 1:3, 3))
wideLSVar
$Y1
[1] "Y11" "Y21" "Y31"

$Y2
[1] "Y12" "Y22" "Y32"

$Y3
[1] "Y13" "Y23" "Y33"
wideLSdat[,names(wideLSVar)] <- sapply(
                X = wideLSVar,
                FUN = function(x) {
                                        
                    ret <- calcScaleScore(data = wideLSdat,
                                          items = x)
                                        
                    return(ret)
                },simplify = F)

head(wideLSdat[,names(wideLSVar)])
         Y1         Y2         Y3
1 -2.680416  2.2974542  3.8943707
2  2.944144  3.4948176  3.1198335
3 -1.403956  1.5638600  2.1539978
4 -2.010152 -2.9952976 -3.7823288
5 -4.117428 -3.3980176  0.6669694
6 -2.701068  0.9692462  3.7553657

When not to loop?

Answer: If vectorization is possible…

Example: Create a large vector (10 million random values) and multiply it by 2.

set.seed(999)
x <- rnorm(1e7)  

Loop approach

system.time({

  y <- numeric(length(x))

  for (i in 1:length(x)) {
    y[i] <- x[i] * 2
  }

})
   user  system elapsed 
   0.72    0.02    0.74 

Vectorizized approach

system.time({

  y <- x * 2

})
   user  system elapsed 
   0.00    0.01    0.01 

But, How to know that vectorization is possible?

→ Especially, in coding situations where you need to perform the same operation on each element1 (e.g., vector, matrix):

  • Arithmetic operations (e.g, +, -, …)
  • Logical comparisons (e.g., ==, >, …)
  • Mathematical functions (e.g., sqrt(), log(), …)

Create Sections in Quarto Programmatically

In this section, we will generate headings by iterating through a named list. The elements of the list will be hyperlinks to Wikipedia, but they can also be other types of content, such as tables or figures.

Named list

someInfo <- list(
    "Apples" = "<https://en.wikipedia.org/wiki/Apple>",
    "Bananas" = "<https://en.wikipedia.org/wiki/Banana>",
    "Oranges" = "<https://en.wikipedia.org/wiki/Orange_(fruit)>"
    )

for loop

To generate the sections (recall, headings are created by using #, ##, etc.) for all elements, we use a for loop. All content is wrapped in the cat() function that concatenates and prints the input to plain text. To tell Quarto to treat the content as raw markdown, we set the output option to asis. For a more detailed description of the code, see the code-annotations below the code.

Be generous with "\n" as it creates a new line.

Code
```{r}
#| label: create-section
#| code-fold: show
1#| output: asis
#| code-annotations: select
2for (i in seq_along(someInfo) ) {
    
    if (i == 1) {
        cat("\n### Programmatically generated headings\n")
        }
    
3    cat("\n#### ", names(someInfo)[i], "\n")
    
    cat("In this section, we provide some information about",
        paste0(tolower(names(someInfo)[i]), ".\n"))
    
4    cat("\n::: {.column-margin}\n", "Link to wikipedia: ",
        someInfo[[i]],
        "\n:::\n")
    
5    cat("\n{{< lipsum 1 >}}\n")
}
```
1
Set output chunk option to asis.
2
Open for loop, which iterates through the someInfo list.
3
State #### before the names(someInfo) object within the cat() function to create sections.
4
(Optional): Positioning content in the margin of the document: Use a div with the .column-margin class.
5
(Optional): Adding placeholder text: {{< lipsum >}}

Programmatically generated headings

Apples

In this section, we provide some information about apples.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Bananas

In this section, we provide some information about bananas.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Oranges

In this section, we provide some information about oranges.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sagittis posuere ligula sit amet lacinia. Duis dignissim pellentesque magna, rhoncus congue sapien finibus mollis. Ut eu sem laoreet, vehicula ipsum in, convallis erat. Vestibulum magna sem, blandit pulvinar augue sit amet, auctor malesuada sapien. Nullam faucibus leo eget eros hendrerit, non laoreet ipsum lacinia. Curabitur cursus diam elit, non tempus ante volutpat a. Quisque hendrerit blandit purus non fringilla. Integer sit amet elit viverra ante dapibus semper. Vestibulum viverra rutrum enim, at luctus enim posuere eu. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Footnotes

  1. so-called element-wise operations↩︎