Search code examples
rdplyrrename

Use of dplyr's rename_with() when no column matches the tidyselect any_of()


I am struggling in using rename_with() with the tidyselector any_of() if there's no match within the latter.

See this example :

library(tidyvese)

iris |> 
  rename_with(.cols = any_of(contains("Length")),
              .fn = ~ifelse(str_detect(.x, "Petal"),
                      paste0(.x,  "_[petal_var]"),
                      paste0(.x, "_[sepal_var]")))

What it does is basically check if there's any variable that contains the string "Length", and then it applies a function according to whether the variable contains the string "Petal" :

  • Yes : then rename with a "_[petal_var]" suffix

  • No: then rename with a "_[sepal_var]" suffix

However, this works as long as there's at least one variable matching the any_of() call.

Let's consider this example where there's no match :

iris |> 
  rename_with(.cols = any_of(contains("UNMATCHED_STRING")),
              .fn = ~ifelse(str_detect(.x, "Petal"),
                      paste0(.x,  "_[petal_var]"),
                      paste0(.x, "_[sepal_var]")))

This returns :

Error in `rename_with()`:
! `.fn` must return a character vector, not an empty logical vector.
Run `rlang::last_error()` to see where the error occurred.

I understand the issue : there's nothing to pass to the .fn argument, since no variable matches the tidyselect .col step.

Unfortunately I see no workaround using rename_with() (which is strongly desired here). In my more complex case, I need to pass fairly complex renaming functions to different datasets which may contain or not the value of any_of(contains(...)).

Any help would be greatly appreciated.


Solution

  • For the discussion of this Issue see: https://github.com/tidyverse/dplyr/issues/6688

    The simplest work around is to set the parameter paste0(recycle0 = TRUE). So in your case this should work:

    iris |> 
      rename_with(.cols = any_of(contains("UNMATCHED_STRING")),
                  .fn = ~ifelse(str_detect(.x, "Petal"),
                          paste0(.x,  "_[petal_var]", recycle0 = TRUE),
                          paste0(.x, "_[sepal_var]", recycle0 = TRUE)))
    

    The dplyr package maintainers have included an example to the rename_with man page to adress this issue.