A year ago I already wrote an article how to iterate over the rows of a data.frame. Now I’ve run into another special case. Last year we used pmap_dfr() to pass each element of a row as single parameter to our custom function.

But what should you do if your function accepts a data.frame (or list) as one single parameter?

The function …

But let’s look at our example first:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
my_function <- function(repeated = 1, text = "a", number_rows = 2) {
  row <- data.frame(
    `repeated` = repeated,
    `text`   = text,
    `number_rows`  = number_rows, 
    generated_text = paste(replicate(repeated, text), collapse = "")
  )
  return(do.call("rbind", replicate(number_rows, row, simplify = FALSE)))
}

my_function(3, "Hello ", 4)
1
2
3
4
5
##   repeated   text number_rows     generated_text
## 1        3 Hello            4 Hello Hello Hello 
## 2        3 Hello            4 Hello Hello Hello 
## 3        3 Hello            4 Hello Hello Hello 
## 4        3 Hello            4 Hello Hello Hello

Let’s change this function a little bit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
my_new_function <- function(input_data) {
  row <- data.frame(
    `repeated` = input_data$repeated,
    `text`   = input_data$text,
    `number_rows`  = input_data$number_rows, 
    generated_text = paste(replicate(input_data$repeated, input_data$text), collapse = "")
  )
  return(do.call("rbind", replicate(input_data$number_rows, row, simplify = FALSE)))
}

input_data <- data.frame(
  repeated = 3,
  text = "Hello ",
  number_rows = 4
)
my_new_function(input_data)
1
2
3
4
5
##   repeated   text number_rows     generated_text
## 1        3 Hello            4 Hello Hello Hello 
## 2        3 Hello            4 Hello Hello Hello 
## 3        3 Hello            4 Hello Hello Hello 
## 4        3 Hello            4 Hello Hello Hello

… and its parameters

Now we want to call the function my_new_function with each row of the following data.frame as parameter:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
options(tidyverse.quiet = TRUE)
library(tidyverse, warn.conflicts = FALSE)
parameters <- tribble(
  ~repeated, ~text, ~number_rows,
  1, "one", 3,
  2, "two", 2,
  3, "three", 1
) %>% 
  as.data.frame()

parameters
1
2
3
4
##   repeated  text number_rows
## 1        1   one           3
## 2        2   two           2
## 3        3 three           1

Iterating again

Using purrr::pmap_dfr() won’t work because our function expects one single argument.

So we use purrr::pmap() to convert each row into a data.frame and combine these data.frames to a list. Then we can use purrr::map_dfr().

1
2
3
parameters %>% 
  purrr::pmap(data.frame) %>% 
  purrr::map_dfr(my_new_function)
1
2
3
4
5
6
7
##   repeated  text number_rows  generated_text
## 1        1   one           3             one
## 2        1   one           3             one
## 3        1   one           3             one
## 4        2   two           2          twotwo
## 5        2   two           2          twotwo
## 6        3 three           1 threethreethree

Notes

When I had found the above solution for my problem I googled for a solution with one single purrr function call. During this search I found this page by Jenny Bryan who is very inspiring for all purrr related stuff.