2

I have a list of tibbles, and a list of columns I wish to convert to date class.

library(tibble)
library(purrr)
library(lubridate)

df1 <- tribble(~date_a,    ~value_a,
               "2017-1-3", 10,
               "2018-2-7", 13,
               "2018-5-7", 35)

df2 <- tribble(~date_b,    ~value_b,
               "2014-1-7", 10,
               "2018-4-9",  6,
               "2018-5-8", 18)

list_dfs <- list(df1, df2)
list_dates <- c("date_a", "date_b")

Trying to use purrr:map, dplyr:mutate_at and lubridate::ymd to efficiently convert these, but getting the following error message:

list_dfs %>% map(~mutate_at(.x, vars(list_dates), ymd))
Error: Strings must match column names. Unknown columns: date_b

This seems similar, but I can't get mapping over tibbles and columns to work.

Do I need to do something clever with purrr::map2?

Peter MacPherson
  • 683
  • 1
  • 7
  • 17

1 Answers1

4

You are correct, you can use purrr::map2 where the first argument will be your list of tibbles and the second the list of column names

list_dfs <- list(df1, df2)
list_dates <- c("date_a", "date_b")

result <- map2(list_dfs, list_dates, ~ mutate_at(.x, .y, ymd))

result

# [[1]]
# # A tibble: 3 x 2
#   date_a     value_a
#   <date>       <dbl>
# 1 2017-01-03     10.
# 2 2018-02-07     13.
# 3 2018-05-07     35.

# [[2]]
# # A tibble: 3 x 2
#   date_b     value_b
#   <date>       <dbl>
# 1 2014-01-07     10.
# 2 2018-04-09      6.
# 3 2018-05-08     18.

for (i in seq_along(result)) {
    assign(paste0("df", i), result[[i]])
}
Relasta
  • 1,066
  • 8
  • 8
  • Thanks - this works. As a follow-up, how would I save these mutated columns within the original tibbles? `map2_df` and `map2_dfc` don't seem to do it – Peter MacPherson May 22 '18 at 09:22
  • @PeterMacPherson I have updated my answer with a possible solution. It will work for your specific example but will not be generalisable if your dataframes are not called df1, df2, df3 etc. – Relasta May 22 '18 at 09:57
  • 1
    If the `list_df` is named (ie: `list_dfs <- list('df1' = df1, 'df2' = df2)`) you can use `list2env(result, envir = .GlobalEnv)` to assign back the variables to the global environment – GGamba May 22 '18 at 10:16
  • Brilliant thanks. Both these comments together solve the problem. – Peter MacPherson May 22 '18 at 10:52
  • 1
    You should probably not do it though. I can't think of a case where it's reasonable to keep numbered data.frames out of a list if it's more than 2 or 3 of them. – moodymudskipper May 22 '18 at 13:42
  • 1
    and if you really must, you can use `tibble::lst(df1,df2)` instead of `list(df1,df2)` and you'll be able to use @GGamba's comment and avoid the loop on `assign`. – moodymudskipper May 22 '18 at 13:45