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.

Map Functions: A Complete Guide

Overview

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.

library(SafeMapper)

Function Family Overview

┌─────────────────────────────────────────────────────────────────────────────┐
│                        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                                      │    │
│   └────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

s_map Family: Single-Input Mapping

s_map - Basic Mapping

# 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

s_map_chr - Return Character Vector

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

s_map_dbl - Return Numeric Vector

# 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

s_map_int - Return Integer Vector

# 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

s_map_lgl - Return Logical Vector

# 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

s_map_dfr - Return Data Frame (Row-Bind)

# 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

s_map_dfc - Return Data Frame (Column-Bind)

# 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 Family: Dual-Input Mapping

┌─────────────────────────────────────────────────────────────────┐
│                    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]                          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

s_map2 Basic Usage

# 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

Practical Examples

# 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: Multi-Input Mapping

┌─────────────────────────────────────────────────────────────────┐
│                    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]                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

s_pmap Basic Usage

# Use named parameter list
params <- list(
  x = 1:3,
  y = 4:6,
  z = 7:9
)

# Calculate x + y * z
results <- s_pmap(params, function(x, y, z) x + y * z)
#> [33%] Processing items 1-3 of 3
#> Completed 3 items
print(unlist(results))
#> [1] 29 42 57

Combining with Data Frames

# 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: Indexed Mapping

┌─────────────────────────────────────────────────────────────────┐
│                    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)                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

s_imap Basic Usage

# 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 Family: Side-Effect Functions

┌─────────────────────────────────────────────────────────────────┐
│                    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                                        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

s_walk Basic Usage

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

s_walk2 Dual-Input Side Effects

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

Function Parameter Passing

All 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.9

Session ID Usage

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

┌─────────────────────────────────────────────────────────────────┐
│                    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  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

Common Patterns

Pattern 1: Data Transformation Pipeline

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

Pattern 2: Conditional Processing

# Execute different operations based on conditions
values <- c(-2, 0, 3, -5, 7)

processed <- s_map_dbl(values, function(x) {
  if (x < 0) abs(x) * 2
  else x^2
})
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(processed)
#> [1]  4  0  9 10 49

Pattern 3: Safe NULL Handling

# Handle data that might contain NULLs
data <- list(a = 1, b = NULL, c = 3, d = NULL, e = 5)

# Use s_map with conditional check
safe_values <- s_map_dbl(data, ~ if (is.null(.x)) NA_real_ else .x)
#> [20%] Processing items 1-5 of 5
#> Completed 5 items
print(safe_values)
#> [1]  1 NA  3 NA  5

Next Steps

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.