Search code examples
rpurrr

How can I simplify the output of `purrr::safely()` and `purrr::map()`?


I would like to turn the results of map(.l, safely(f))) into a data frame.

For example,

# define function
sum_of_dimensions <- function(df){
  stopifnot(nrow(df) < 150)
  result <- nrow(df) + ncol(df)
  return(result)
}

# create list of data frames over which to map
dfs <- list(mtcars = mtcars, iris = iris)

# safely map over dfs
list_safe <- 
  purrr::map(
    dfs,
    purrr::safely(sum_of_dimensions)
  )

# desired results
#>   item   result       error       
#>   <chr>  <named list> <named list>
#> 1 mtcars <int [1]>    <NULL>      
#> 2 iris   <NULL>       <smplErrr>

Created on 2023-04-21 with reprex v2.0.2


Solution

  • It looks like you can create the output you want with

      purrr::map(
        dfs,
        purrr::safely(sum_of_dimensions)
      ) %>% tibble::enframe() %>% 
      tidyr::hoist(value, "result","error", .simplify=FALSE)
    

    which returns

      name   result    error     
      <chr>  <list>    <list>    
    1 mtcars <int [1]> <NULL>    
    2 iris   <NULL>    <smplErrr>
    

    We use enframe() to turn the result into a data.frame keeping the list names as a column, then we use hoist to extract the nested values. Setting .simplify=FALSE keeps everything in list columns.