The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
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[@]metanet.ch.
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.