当某些元素为空时重命名嵌套列表

问题描述 投票:0回答:2

如何使用

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 上发现了这个问题,但仍然存在问题

r purrr
2个回答
0
投票

这是一个具有自定义功能的解决方案:

通过此函数,我们通过将

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   

0
投票

您无需事先显式重命名即可执行此操作。您只需要对内部列表进行行绑定,然后对结果和数据透视进行绑定。

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      
© www.soinside.com 2019 - 2024. All rights reserved.