I already posted this as an issue in dplyr's repo on github, and they said that across is not a good fit for this type of problem, but I want to post here to see if anyone can give me insight into why this doesn't actually work.
I'm trying to write a function that takes a data frame (y) and uses it to update the column classes of another data frame (x) by matching column names. I had this code lying around and when I wrote it about a year ago I could've swore it worked, but now it doesn't seem to.
library(tidyverse)
(x = tibble(data.frame(a = as.character(c(1,2,3,4)),
b = as.character(c(1,2,3,4)),
c = as.character(c(1,2,3,4)),
d = as.character(c('a', 'b', 'c', 'd')))))
#> # A tibble: 4 × 4
#> a b c d
#> <chr> <chr> <chr> <chr>
#> 1 1 1 1 a
#> 2 2 2 2 b
#> 3 3 3 3 c
#> 4 4 4 4 d
(y = tibble(data.frame(a = as.numeric(c(1,1,1,1)),
b = as.character(c(1,1,1,1)),
c = as.numeric(c(1,1,1,1)),
d = as.character(c('a', 'a', 'a', 'a')))))
#> # A tibble: 4 × 4
#> a b c d
#> <dbl> <chr> <dbl> <chr>
#> 1 1 1 1 a
#> 2 1 1 1 a
#> 3 1 1 1 a
#> 4 1 1 1 a
## this code i have in my function gives an error
result <-
x %>%
dplyr::mutate( dplyr::across( .cols = tidyselect::all_of( colnames( y ) ),
.fns = ~eval(parse(text = paste0(
"as.",
class( y[[dplyr::cur_column()]] ),
"(.)"
)))))
#> Error in `dplyr::mutate()`:
#> ! Problem while computing `..1 = dplyr::across(...)`.
#> Caused by error in `across()`:
#> ! Problem while computing column `a`.
#> Caused by error:
#> ! 'list' object cannot be coerced to type 'double'
#> Backtrace:
#> ▆
#> 1. ├─x %>% ...
#> 2. ├─dplyr::mutate(...)
#> 3. ├─dplyr:::mutate.data.frame(...)
#> 4. │ └─dplyr:::mutate_cols(.data, dplyr_quosures(...), caller_env = caller_env())
#> 5. │ ├─base::withCallingHandlers(...)
#> 6. │ ├─base::withCallingHandlers(...)
#> 7. │ └─mask$eval_all_mutate(quo)
#> 8. ├─base::eval(...)
#> 9. │ └─base::eval(...)
#> 10. └─base::.handleSimpleError(...)
#> 11. └─dplyr (local) h(simpleError(msg, call))
#> 12. └─rlang::abort(msg, call = call("across"), parent = cnd)
## and my desired result is:
result = data.frame(a = as.numeric(1,2,3,4),
b = as.character(1,2,3,4),
c = as.numeric(1,2,3,4),
d = as.character('a', 'b', 'c', 'd'))
This seems like a crazy way to achieve the end goal here. A short one-liner using
map2_df
would do the same thing:As for why your code doesn't work, you are right in the sense that this is due to the way that
eval
works inside a lambda function (it is taking the.
as referring to the data frame that was passed into the function call, not as a placeholder to be used inside the lambda function). This is why it is warning you about alist
.If you change the lambda function to a standard function it will work as expected.