For Loop in R with Examples for List and Matrix

โšก Smart Summary

For Loop in R runs a block of code once for every element of a sequence, whether that sequence is a vector, a list, or a matrix. This walkthrough iterates over each of them and shows when vectorized code is the better choice.

  • ๐Ÿ” Core Syntax: for (i in vector) { expression } assigns each element to i in turn and runs the body.
  • ๐Ÿ“‹ Any Object: The same syntax walks a vector, a list, a data frame column set, or the rows of a matrix.
  • ๐Ÿงฎ Nested Loops: A matrix needs two loops, an outer one for rows and an inner one for columns.
  • ๐Ÿ›‘ Flow Control: break leaves the loop entirely and next skips only the current element.
  • โšก Vectorization First: Built-in vectorized operations and the apply family are faster and shorter than an explicit loop.
  • โš ๏ธ Safe Sequences: Use seq_along(x) rather than 1:length(x), which misbehaves when the object is empty.

For Loop in R List Matrix

A for loop repeats a block of code once for every element of a sequence. That sequence can be a vector, a list, a data frame, a matrix, or any other object R can iterate over. R is case-sensitive, so the keyword is always lowercase for, and the curly braces are required whenever the body spans more than one line.

For Loop Syntax in R

for (i in vector) {
    Exp
}

Here,

R will loop over all the variables in vector and do the computation written inside the exp.

For Loop in R
For Loop in R

Let’s see a few examples.

For Loop in R Example 1: We iterate over all the elements of a vector and print the current value.

# Create fruit vector
fruit <- c('Apple', 'Orange', 'Passion fruit', 'Banana')
# Create the for statement
for ( i in fruit){ 
 print(i)
}

Output:

## [1] "Apple"
## [1] "Orange"
## [1] "Passion fruit"
## [1] "Banana"

For Loop in R Example 2: square every integer from 1 to 4 and store the results in a list.

# Create an empty list
list <- c()
# Create a for statement to populate the list
for (i in seq(1, 4, by=1)) {
  list[[i]] <- i*i
}
print(list)

Output:

## [1]   1  4 9 16

For loops are useful in machine learning work. Tuning a regularization parameter means testing many candidate values and keeping the one that minimises the loss function, and a for loop is the straightforward way to sweep that range.

How to Use break and next in a For Loop

Two keywords interrupt the normal sequence of a for loop.

  • break exits the loop immediately and skips every remaining element.
  • next abandons the current element only and moves on to the following one.
fruit <- c('Apple', 'Orange', 'Passion fruit', 'Banana')

# break: stop at the first match
for (i in fruit) {
    if (i == 'Passion fruit') {
        print('Found it, stopping here')
        break
    }
    print(i)
}

# next: skip one element and carry on
for (i in fruit) {
    if (i == 'Orange') next
    print(i)
}

In nested loops, break and next act only on the innermost loop that contains them. To leave both loops in the matrix example, set a flag variable and test it in the outer loop as well.

Use seq_along() for indexes. Writing for (i in 1:length(x)) looks harmless but fails on an empty object, because 1:0 produces the sequence 1, 0 and the loop runs twice. seq_along(x) returns an empty sequence instead, so the loop is correctly skipped:

for (i in seq_along(fruit)) {
    cat(i, fruit[i], '\n')
}

For Loop Over a List

Looping over a list works exactly like looping over a vector, except that each element can hold a different type:

# Create a list with three vectors
fruit <- list(Basket = c('Apple', 'Orange', 'Passion fruit', 'Banana'), 
Money = c(10, 12, 15), purchase = FALSE)
for (p  in fruit) 
{ 
	print(p)
}

Output:

## [1] "Apple" "Orange" "Passion fruit" "Banana"       
## [1] 10 12 15
## [1] FALSE

For Loop Over a Matrix

A matrix has two dimensions, rows and columns, so iterating over every cell needs two nested for loops: an outer one for the rows and an inner one for the columns.

# Create a matrix
mat <- matrix(data = seq(10, 20, by=1), nrow = 6, ncol =2)
# Create the loop with r and c to iterate over the matrix
for (r in 1:nrow(mat))   
    for (c in 1:ncol(mat))  
         print(paste("Row", r, "and column",c, "have values of", mat[r,c]))  

Output:

## [1] "Row 1 and column 1 have values of 10"
## [1] "Row 1 and column 2 have values of 16"
## [1] "Row 2 and column 1 have values of 11"
## [1] "Row 2 and column 2 have values of 17"
## [1] "Row 3 and column 1 have values of 12"
## [1] "Row 3 and column 2 have values of 18"
## [1] "Row 4 and column 1 have values of 13"
## [1] "Row 4 and column 2 have values of 19"
## [1] "Row 5 and column 1 have values of 14"
## [1] "Row 5 and column 2 have values of 20"
## [1] "Row 6 and column 1 have values of 15"
## [1] "Row 6 and column 2 have values of 10" 

For Loop Over a Data Frame in R

A data frame is a list of columns, so a plain for loop walks its columns rather than its rows. That is usually what you want:

df <- data.frame(a = 1:5, b = 6:10, c = 11:15)

# Loop over the columns
for (col in names(df)) {
    cat(col, 'has mean', mean(df[[col]]), '\n')
}

Note the double bracket. df[[col]] extracts the column as a vector, whereas df[col] returns a one-column data frame that mean() cannot handle.

Looping over rows. Row-wise iteration is possible but slow, because R copies the row on every pass:

for (r in seq_len(nrow(df))) {
    cat('Row', r, 'sums to', sum(df[r, ]), '\n')
}

For anything beyond a few thousand rows, prefer rowSums(df), apply(df, 1, sum), or a dplyr group_by() and summarise() pipeline, all of which do the same work without the copying.

For Loops vs Vectorization in R

R is a vectorized language: most of its operators and functions already act on whole vectors at once, in compiled C code. An explicit loop that repeats a vectorized operation element by element is both longer and slower.

# Loop version
squares <- c()
for (i in 1:4) {
    squares[i] <- i * i
}

# Vectorized version, same result
squares <- (1:4)^2
Task Loop Vectorized equivalent
Element-wise arithmetic for over each element x * 2, x + y, x^2
Apply a function per column for over names(df) sapply(df, mean)
Apply a function per row for over seq_len(nrow(df)) apply(df, 1, sum)
Build a list of results for with list[[i]] <- … lapply(v, f)
Conditional recoding for with if and else ifelse(cond, a, b)

When a loop is still the right answer. Keep the for loop when each iteration depends on the previous result, when you are calling an external service or writing files, or when clarity matters more than speed on a small object.

If you must loop, preallocate. Growing an object inside a loop forces R to copy it on every pass. Create it at full size first:

# Slow: the vector is reallocated on every pass
out <- c()
for (i in 1:1000) out[i] <- i^2

# Fast: allocated once
out <- numeric(1000)
for (i in 1:1000) out[i] <- i^2

For Loop in R: Quick Reference

Every construct used in this tutorial is listed below:

Objective Code
Loop over a vector
for (i in v) { print(i) }
Loop over indexes safely
for (i in seq_along(v)) { print(v[i]) }
Loop over a list
for (p in my_list) { print(p) }
Loop over data frame columns
for (col in names(df)) { print(mean(df[[col]])) }
Loop over a matrix
for (r in 1:nrow(m)) for (c in 1:ncol(m)) print(m[r, c])
Exit the loop early
if (condition) break
Skip one iteration
if (condition) next
Preallocate the output
out <- numeric(n)

FAQs

When x is empty, 1:length(x) returns the sequence 1, 0 and the loop runs twice on non-existent elements. seq_along(x) returns an empty sequence, so the loop is correctly skipped.

The loop itself is not the problem. Growing an object inside it is, because R copies the whole object on every pass. Preallocate the result, or use a vectorized function, and the gap largely disappears.

Columns. A data frame is a list of columns, so each iteration hands you one whole column. Use seq_len(nrow(df)) explicitly if you need to walk the rows instead.

For loops drive hyperparameter sweeps, cross-validation folds, and training epochs. Each of these has a known iteration count, which is exactly what the for construct is designed for.

Yes. AI assistants can convert most element-wise loops into vectorized or apply-family equivalents. Compare the output of both versions with identical() before replacing the original.

Summarize this post with: