I have a named list and within that list I want to rename their columns based on the names the list comes from.
The probelm with my approach seems to be the .x
placeholder, which I thought would be my unique list names. But within the rename_with
function, it seems the .x
is evaluated within each list data frame and not from the original .x
. Is there any way I can carry forward the original .x
(or list names) for renaming?
my_list <- list(L1 = data.frame(x=1:3),
L1 = data.frame(x=1:3),
L2 = data.frame(x=1:3),
L2 = data.frame(x=1:3))
my_list |>
purrr::map(.x = unique(names(my_list)),
.f = ~my_list[names(my_list) == .x] |>
dplyr::bind_rows() |>
dplyr::rename_with(.cols = "x",
.fn = ~paste0("new_", .x)))
expected output:
[[1]]
new_L1
1 1
2 2
3 3
4 1
5 2
6 3
[[2]]
new_L2
1 1
2 2
3 3
4 1
5 2
6 3
CodePudding user response:
Just revise 2 places:
You have set
.x
and.f
formap()
, so the first line (my_list |>
) is redundant. It makesmy_list
thrown into the...
part ofmap()
, which works on nothing.In the
.fn
part ofrename_with()
, if you use a formula-style function, the placeholder.x
will conflict. So you should use a basic function and set a different argument name.
purrr::map(.x = unique(names(my_list)),
.f = ~ my_list[names(my_list) == .x] |>
dplyr::bind_rows() |>
dplyr::rename_with(.cols = "x",
.fn = \(col) paste0("new_", .x)))
[[1]]
new_L1
1 1
2 2
3 3
4 1
5 2
6 3
[[2]]
new_L2
1 1
2 2
3 3
4 1
5 2
6 3
You could also use rename
so that you don't worry about the conflict.
|> dplyr::rename(!!paste0("new_", .x) := x)
CodePudding user response:
Another approach I like to use to avoid .x
conflicts is to use an anonymous function for map
:
unique(names(my_list)) |>
# if you want a named list, use set_names
# purrr::set_names() |>
purrr::map(\(list_name) my_list[names(my_list) == list_name] |>
dplyr::bind_rows() |>
dplyr::rename_with(.cols = "x",
.fn = ~paste0("new_", list_name))
)
CodePudding user response:
Another option could be:
imap(my_list,
~ .x %>%
rename_with(function(listnames) paste0("new_", .y), everything()))
$L1
new_L1
1 1
2 2
3 3
$L1
new_L1
1 1
2 2
3 3
$L2
new_L2
1 1
2 2
3 3
$L2
new_L2
1 1
2 2
3 3
If you need an unnamed list:
imap(my_list,
~ .x %>%
rename_with(function(listnames) paste0("new_", .y), everything())) %>%
unname()