Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rename_with() errors when no match/clarity of error message #6945

Closed
asadow opened this issue Oct 26, 2023 · 2 comments
Closed

rename_with() errors when no match/clarity of error message #6945

asadow opened this issue Oct 26, 2023 · 2 comments

Comments

@asadow
Copy link

asadow commented Oct 26, 2023

I thought I could use map over a list of data frames to rename them using rename_with() and a tidyselector like matches(), whether or not each data frame has a matching column name. Now it looks as though that is not longer possible (#6688).

That's all fine and good. Now I see I can just use rename(), which does not error. But I think the error for rename_with() could be more clear by saying that there is no match.

Lastly, I'm curious: why the difference in erroring vs. not between rename() and rename_with()?

library(tidyverse)

# No error
mtcars |> rename("joe" = matches("qwerty")) |> head(1)
#>           mpg cyl disp  hp drat   wt  qsec vs am gear carb
#> Mazda RX4  21   6  160 110  3.9 2.62 16.46  0  1    4    4

# Hinting error
mtcars |> rename_with(~ "joe", qwerty)
#> Error in `rename_with()`:
#> ! Can't subset columns that don't exist.
#> ✖ Column `qwerty` doesn't exist.
#> Backtrace:
#>      ▆
#>   1. ├─dplyr::rename_with(mtcars, ~"joe", qwerty)
#>   2. ├─dplyr:::rename_with.data.frame(mtcars, ~"joe", qwerty)
#>   3. │ └─tidyselect::eval_select(enquo(.cols), .data, allow_rename = FALSE)
#>   4. │   └─tidyselect:::eval_select_impl(...)
#>   5. │     ├─tidyselect:::with_subscript_errors(...)
#>   6. │     │ └─rlang::try_fetch(...)
#>   7. │     │   └─base::withCallingHandlers(...)
#>   8. │     └─tidyselect:::vars_select_eval(...)
#>   9. │       └─tidyselect:::walk_data_tree(expr, data_mask, context_mask)
#>  10. │         └─tidyselect:::as_indices_sel_impl(...)
#>  11. │           └─tidyselect:::as_indices_impl(...)
#>  12. │             └─tidyselect:::chr_as_locations(x, vars, call = call, arg = arg)
#>  13. │               └─vctrs::vec_as_location(...)
#>  14. └─vctrs (local) `<fn>`()
#>  15.   └─vctrs:::stop_subscript_oob(...)
#>  16.     └─vctrs:::stop_subscript(...)
#>  17.       └─rlang::abort(...)

# Less helpful error
mtcars |> rename_with(~ "joe", matches("qwerty"))
#> Error in `rename_with()`:
#> ! `.fn` must return a vector of length 0, not 1.
#> Backtrace:
#>     ▆
#>  1. ├─dplyr::rename_with(mtcars, ~"joe", matches("qwerty"))
#>  2. └─dplyr:::rename_with.data.frame(mtcars, ~"joe", matches("qwerty"))
#>  3.   └─cli::cli_abort("{.arg .fn} must return a vector of length {length(sel)}, not {length(new)}.")
#>  4.     └─rlang::abort(...)

Created on 2023-10-26 with reprex v2.0.2

@DavisVaughan
Copy link
Member

It isn't really the fact that there is no match in matches("qwerty") that is the problem. That's totally fine. It's the fact that you matched 0 column names (i.e. the input to your .fn) but the output has length 1 ("joe").

rename_with() isn't really meant to be used with a static result like that, it is more often used where you take the input, apply some transformation, and return some output of the same size, like .fn = ~ stringr::str_c("blah.", .x).

So I think it is probably just the wrong function for what you were trying to do

@asadow
Copy link
Author

asadow commented Nov 6, 2023

I agree; the doc's say rename() should be used for individual columns.

I think my 2 points are still worth considering:

  1. The rename_with() error is not very user-friendly.
  2. rename_with() and rename() behave inconsistently: mtcars |> rename("joe" = matches("qwerty")) returns the data, but mtcars |> rename_with(~ "joe", matches("qwerty")) does not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants