The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
SafeMapper provides a complete family of mapping functions that correspond to all common functions in purrr. This article details the usage and best practices for each function.
┌─────────────────────────────────────────────────────────────────────────────┐
│ SafeMapper Map Function Family │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Single-Input Mapping (s_map family) │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ s_map ──► returns list │ │
│ │ s_map_chr ──► returns character vector │ │
│ │ s_map_dbl ──► returns numeric vector │ │
│ │ s_map_int ──► returns integer vector │ │
│ │ s_map_lgl ──► returns logical vector │ │
│ │ s_map_dfr ──► returns data.frame (row-bind) │ │
│ │ s_map_dfc ──► returns data.frame (column-bind) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ Dual-Input Mapping (s_map2 family) │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ s_map2 ──► iterate two vectors simultaneously │ │
│ │ s_map2_chr ──► returns character vector │ │
│ │ s_map2_dbl ──► returns numeric vector │ │
│ │ s_map2_int ──► returns integer vector │ │
│ │ s_map2_lgl ──► returns logical vector │ │
│ │ s_map2_dfr ──► returns data.frame (row-bind) │ │
│ │ s_map2_dfc ──► returns data.frame (column-bind) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ Multi-Input Mapping │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ s_pmap ──► iterate multiple vectors (parallel map) │ │
│ │ s_imap ──► iterate with index (indexed map) │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
│ Side-Effect Functions │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ s_walk ──► execute side effects only, no return │ │
│ │ s_walk2 ──► dual-input walk │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
# Basic usage: returns a list
squares <- s_map(1:5, function(x) x^2)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(squares)
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 4
#>
#> [[3]]
#> [1] 9
#>
#> [[4]]
#> [1] 16
#>
#> [[5]]
#> [1] 25
# Using formula syntax (recommended)
squares <- s_map(1:5, ~ .x^2)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(unlist(squares))
#> [1] 1 4 9 16 25# Convert numbers to formatted strings
labels <- s_map_chr(1:5, ~ paste0("Item_", .x))
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(labels)
#> [1] "Item_1" "Item_2" "Item_3" "Item_4" "Item_5"
# Extract character elements from lists
persons <- list(
list(name = "Alice", age = 25),
list(name = "Bob", age = 30),
list(name = "Carol", age = 28)
)
names <- s_map_chr(persons, ~ .x$name)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(names)
#> [1] "Alice" "Bob" "Carol"# Calculate square roots
roots <- s_map_dbl(c(1, 4, 9, 16, 25), sqrt)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(roots)
#> [1] 1 2 3 4 5
# Statistical calculations
datasets <- list(
a = rnorm(100, mean = 0),
b = rnorm(100, mean = 5),
c = rnorm(100, mean = 10)
)
means <- s_map_dbl(datasets, mean)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(means)
#> [1] -0.003877895 5.010485147 10.005635605# Calculate string lengths
words <- c("apple", "banana", "cherry")
lengths <- s_map_int(words, nchar)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(lengths)
#> [1] 5 6 6
# Count list elements
nested <- list(1:3, 1:5, 1:10)
counts <- s_map_int(nested, length)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(counts)
#> [1] 3 5 10# Check conditions
numbers <- c(2, 5, 8, 12, 15)
is_even <- s_map_lgl(numbers, ~ .x %% 2 == 0)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(is_even)
#> [1] TRUE FALSE TRUE TRUE FALSE
# Check for null values
data <- list(a = 1, b = NULL, c = 3, d = NULL)
has_value <- s_map_lgl(data, ~ !is.null(.x))
#> [25%] Processing items 1-4 of 4
#> Completed 4 items
print(has_value)
#> [1] TRUE FALSE TRUE FALSE# Create multiple data frames and row-bind
create_record <- function(id) {
data.frame(
id = id,
value = rnorm(1),
timestamp = Sys.time()
)
}
records <- s_map_dfr(1:5, create_record)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(records)
#> id value timestamp
#> 1 1 -1.08470348 2026-01-27 18:25:30
#> 2 2 -0.08012704 2026-01-27 18:25:30
#> 3 3 -1.06908549 2026-01-27 18:25:30
#> 4 4 0.83752018 2026-01-27 18:25:30
#> 5 5 0.77986584 2026-01-27 18:25:30# Create multiple columns and column-bind
create_column <- function(name) {
df <- data.frame(x = rnorm(3))
names(df) <- name
df
}
columns <- s_map_dfc(c("A", "B", "C"), create_column)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(columns)
#> A B C
#> 1 0.2930605 -0.3746742 -0.5969886
#> 2 0.4803021 -1.1844813 -0.7081163
#> 3 -0.2664076 -1.7980704 0.9795393┌─────────────────────────────────────────────────────────────────┐
│ s_map2 How It Works │
├─────────────────────────────────────────────────────────────────┤
│ │
│ .x = [a1, a2, a3, a4, a5] │
│ .y = [b1, b2, b3, b4, b5] │
│ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ │
│ .f(a1,b1) .f(a2,b2) .f(a3,b3) .f(a4,b4) .f(a5,b5) │
│ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ │
│ Result: [r1, r2, r3, r4, r5] │
│ │
└─────────────────────────────────────────────────────────────────┘
# Process two vectors simultaneously
x <- 1:5
y <- 10:14
# Calculate sums
sums <- s_map2(x, y, ~ .x + .y)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(unlist(sums))
#> [1] 11 13 15 17 19
# Calculate products
products <- s_map2_dbl(x, y, ~ .x * .y)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(products)
#> [1] 10 22 36 52 70# Batch create file paths
dirs <- c("data", "output", "logs")
files <- c("results.csv", "summary.txt", "debug.log")
paths <- s_map2_chr(dirs, files, ~ file.path(.x, .y))
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(paths)
#> [1] "data/results.csv" "output/summary.txt" "logs/debug.log"
# Compare two vectors
a <- c(1, 5, 3, 8, 2)
b <- c(2, 3, 5, 6, 4)
comparison <- s_map2_chr(a, b, function(x, y) {
if (x > y) "greater"
else if (x < y) "less"
else "equal"
})
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(comparison)
#> [1] "less" "greater" "less" "greater" "less"┌─────────────────────────────────────────────────────────────────┐
│ s_pmap How It Works │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Input list: │
│ .l = list( │
│ a = [a1, a2, a3], │
│ b = [b1, b2, b3], │
│ c = [c1, c2, c3] │
│ ) │
│ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ │
│ .f(a1,b1,c1) .f(a2,b2,c2) .f(a3,b3,c3) │
│ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ │
│ Result: [r1, r2, r3] │
│ │
└─────────────────────────────────────────────────────────────────┘
# Iterate over data frame rows
df <- data.frame(
name = c("Alice", "Bob", "Carol"),
age = c(25, 30, 28),
city = c("New York", "London", "Tokyo")
)
# Create description for each row
descriptions <- s_pmap(df, function(name, age, city) {
sprintf("%s is %d years old and lives in %s", name, age, city)
})
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(unlist(descriptions))
#> [1] "Alice is 25 years old and lives in New York"
#> [2] "Bob is 30 years old and lives in London"
#> [3] "Carol is 28 years old and lives in Tokyo"┌─────────────────────────────────────────────────────────────────┐
│ s_imap How It Works │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Named vector: Unnamed vector: │
│ .x = c(a=10, b=20, c=30) .x = c(10, 20, 30) │
│ │
│ In .f(.x, .y): In .f(.x, .y): │
│ .x = value .x = value │
│ .y = name .y = position index │
│ │
│ .f(10, "a") .f(10, 1) │
│ .f(20, "b") .f(20, 2) │
│ .f(30, "c") .f(30, 3) │
│ │
└─────────────────────────────────────────────────────────────────┘
# Use named vector
scores <- c(math = 85, english = 92, science = 78)
report <- s_imap(scores, ~ sprintf("%s: %d points", .y, .x))
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(unlist(report))
#> [1] "math: 85 points" "english: 92 points" "science: 78 points"
# Use unnamed vector (get position index)
items <- c("apple", "banana", "cherry")
indexed <- s_imap(items, ~ sprintf("[%s] %s", .y, .x))
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(unlist(indexed))
#> [1] "[1] apple" "[2] banana" "[3] cherry"┌─────────────────────────────────────────────────────────────────┐
│ s_walk vs s_map │
├─────────────────────────────────────────────────────────────────┤
│ │
│ s_map: │
│ ├── Execute function │
│ ├── Collect return values │
│ └── Return result list │
│ │
│ s_walk: │
│ ├── Execute function (usually side effects) │
│ ├── Ignore return values │
│ └── Return input (for piping) │
│ │
│ Use cases: │
│ ├── Writing to files │
│ ├── Printing output │
│ ├── Sending network requests (don't care about response) │
│ └── Updating databases │
│ │
└─────────────────────────────────────────────────────────────────┘
# Print output
s_walk(1:3, ~ cat("Processing item", .x, "\n"))
#> [33%] Processing items 1-3 of 3
#> Processing item 1
#> Processing item 2
#> Processing item 3
#> Completed 3 items
# Can be used in pipelines
result <- 1:5 |>
s_walk(~ cat("Checking", .x, "...\n")) |>
# s_walk returns original input, can continue processing
sum()
#> [20%] Processing items 1-5 of 5
#> Checking 1 ...
#> Checking 2 ...
#> Checking 3 ...
#> Checking 4 ...
#> Checking 5 ...
#> Completed 5 items
print(paste("Sum:", result))
#> [1] "Sum: 15"# Batch write (example: print instead of actual write)
files <- c("file1.txt", "file2.txt", "file3.txt")
contents <- c("Content A", "Content B", "Content C")
s_walk2(files, contents, function(f, c) {
cat(sprintf("Would write to %s: '%s'\n", f, c))
})
#> [33%] Processing items 1-3 of 3
#> Would write to file1.txt: 'Content A'
#> Would write to file2.txt: 'Content B'
#> Would write to file3.txt: 'Content C'
#> Completed 3 itemsAll s_map family functions support passing additional
arguments via ...:
# Pass additional arguments to function
data <- list(
c(1, 2, NA, 4),
c(5, NA, 7, 8),
c(9, 10, 11, NA)
)
# Pass na.rm = TRUE to mean function
means <- s_map_dbl(data, mean, na.rm = TRUE)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(means)
#> [1] 2.333333 6.666667 10.000000
# Multiple additional arguments
rounded <- s_map_dbl(c(1.234, 2.567, 3.891), round, digits = 1)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(rounded)
#> [1] 1.2 2.6 3.9All mapping functions support the .session_id
parameter:
# Auto-generate session ID (recommended for most scenarios)
result1 <- s_map(1:10, ~ .x^2)
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
# Manually specify session ID (for precise control scenarios)
result2 <- s_map(1:10, ~ .x^2, .session_id = "my_calculation_v1")
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
# Different session IDs don't affect each other
result3 <- s_map(1:10, ~ .x^2, .session_id = "my_calculation_v2")
#> [10%] Processing items 1-10 of 10
#> Completed 10 items┌─────────────────────────────────────────────────────────────────┐
│ Performance Optimization Tips │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Batch Size Selection │
│ ├── Fast ops (< 10ms/item): batch_size = 500-1000 │
│ ├── Medium ops (10-100ms/item): batch_size = 100 (default) │
│ └── Slow ops (> 100ms/item): batch_size = 10-50 │
│ │
│ 2. Choose Appropriate Output Type │
│ ├── s_map: Most flexible, but more memory │
│ └── s_map_dbl/chr/lgl: More compact, better performance │
│ │
│ 3. Use Parallel Versions │
│ ├── CPU-intensive tasks ──► s_future_map │
│ └── I/O-intensive tasks ──► Usually no parallelism needed │
│ │
└─────────────────────────────────────────────────────────────────┘
# Use pipeline for data transformation
data <- 1:10
result <- data |>
s_map_dbl(~ .x^2) |> # Square
s_map_dbl(~ .x + 10) |> # Add 10
s_map_chr(~ sprintf("%.1f", .x)) # Format
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
#> [10%] Processing items 1-10 of 10
#> Completed 10 items
print(result)
#> [1] "11.0" "14.0" "19.0" "26.0" "35.0" "46.0" "59.0" "74.0" "91.0"
#> [10] "110.0"These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.