如何使用
purrr
重命名可能有值或没有值的嵌套列表?我尝试过 modify_at()
但如果其中一个列表为空,则会出现错误
library(tidyverse)
my_list <-
list(
list(
app = list(id = 123, name = "abc"),
tag = list(id = 456, name = "def")
),
list(
app = list(id = 345, name = "xyz"),
tag = list(id = 678, name = "abc") # <--- works
# tag = NULL # <--- doesn't work
)
)
我希望
app$id
和 app$name
变成 app_id
和 app_name
并最终返回一个数据框
| app_id | app_name | tag_id | tag_name |
|--------|----------|--------|----------|
| 123 | abc | 456 | def |
| 345 | xyz | | |
如果两个应用程序都有标签,则此示例有效,但如果任何标签是
null
(切换上面的注释),则 modify_at("tag")
步骤将失败
my_list |>
map(
~.x |>
modify_at("app", ~set_names(.x, glue("app_{names(.x)}"))) |>
modify_at("tag", ~set_names(.x, glue("tag_{names(.x)}"))) |>
as.data.frame() |> # also why doesn't as_tibble() work here?
rename_all(str_replace_all, "\\.", "_")
) |>
list_rbind()
具体来说,这里:
my_list |>
map(
~modify_at(.x, "tag", ~set_names(.x, glue("tag_{names(.x)}")))
)
# Error in `map()`:
# ℹ In index: 2.
# Caused by error in `map()`:
# ℹ In index: 1.
# ℹ With name: tag.
# Caused by error in `set_names()`:
# ! `x` must be a vector
我在 GitHub 上发现了这个问题,但仍然存在问题
这是一个具有自定义功能的解决方案:
通过此函数,我们通过将
NULL
元素替换为 NA
元素列表来处理它们。然后我们使用 map_vec
将列表转换为数据框。
library(tidyverse)
my_func <- function(list, prefix) {
if(is.null(list)) {
list <- list(id = NA, name = NA)
}
set_names(list, paste0(prefix, "_", names(list)))
}
my_list |>
map(
~ list(
app = my_func(.x$app, "app"),
tag = my_func(.x$tag, "tag")
)
) |>
map_vec(
~ bind_cols(.x$app, .x$tag)
)
app_id app_name tag_id tag_name
<dbl> <chr> <dbl> <chr>
1 123 abc 456 def
2 345 xyz NA NA
您无需事先显式重命名即可执行此操作。您只需要对内部列表进行行绑定,然后对结果和数据透视进行绑定。
library(tidyverse)
my_list |>
map(bind_rows, .id = "element") |>
bind_rows(.id = "list_id") |>
pivot_wider(names_from = element,
values_from = c(id, name),
names_glue = "{element}_{.value}",
names_vary = "slowest")
# A tibble: 2 × 5
list_id app_id app_name tag_id tag_name
<chr> <dbl> <chr> <dbl> <chr>
1 1 123 abc 456 def
2 2 345 xyz NA NA