展平嵌套列表并保留每个底层元素的所有父键
Flatten nested list and retain all parent keys for each bottom-level element
我需要将一个任意嵌套列表展平到一个数据框,并在一列中保留键/索引的路径,同时将底层的每个元素提取到一个单独的元素行。
考虑以下列表:
lst <- list(
animals = list(
lamas = c("brown", "white"),
primates = list(
humans = c("asia", "europe"),
apes = c("good", "fast", "angry")
)
),
objects = c("expensive", "cheap"),
plants = NULL
)
flatten_list(lst, delimiter="_")
的结果应该如下所示:
data.frame(
path = c("animals_lamas", "animals_lamas", "animals_primates_humans", "animals_primates_humans", "animals_primates_apes", "animals_primates_apes", "animals_primates_apes", "objects", "objects", "plants"),
value = c("brown", "white", "asia", "europe", "good", "fast", "angry", "expensive", "cheap", NA)
)
令我惊讶的是我无法使用 tidyr 或 data.tables 实现这一目标。我是否需要递归函数,或者是否有一些开箱即用的解决方案?赞赏!
编辑: akrun 提供的解决方案适用于原始数据。我意识到当元素在底层 NULL
时会出现问题,因此改写了问题。
EDIT2 我目前的解决方法是在应用 akrun 解决方案之前递归地用 NA
替换 NULL
,使用函数 [再次由 akrun ;)].
可以通过 melt
进入 data.frame 然后 unite
键列
来完成
library(reshape2)
library(dplyr)
library(tidyr)
out2 <- melt(lst) %>%
unite(path, L1:L3, sep = "_", na.rm = TRUE) %>%
select(path, value)
-检查 OP 的输出
> all.equal(out, out2)
[1] TRUE
我们也可以用 unlist
和 stack
来自 base R
stack(unlist(lapply(lst, \(x) if(is.null(x)) NA_character_ else x)))[2:1]
可以对付NULL
的解决方案,基于rrapply
:
library(tidyverse)
library(rrapply)
rrapply(lst, f = \(x) if (is.null(x)) NA else x, how = "melt") %>%
unnest(value) %>% unite(path, L1:L3, na.rm = T)
#> # A tibble: 10 × 2
#> path value
#> <chr> <chr>
#> 1 animals_lamas brown
#> 2 animals_lamas white
#> 3 animals_primates_humans asia
#> 4 animals_primates_humans europe
#> 5 animals_primates_apes good
#> 6 animals_primates_apes fast
#> 7 animals_primates_apes angry
#> 8 objects expensive
#> 9 objects cheap
#> 10 plants <NA>
我需要将一个任意嵌套列表展平到一个数据框,并在一列中保留键/索引的路径,同时将底层的每个元素提取到一个单独的元素行。
考虑以下列表:
lst <- list(
animals = list(
lamas = c("brown", "white"),
primates = list(
humans = c("asia", "europe"),
apes = c("good", "fast", "angry")
)
),
objects = c("expensive", "cheap"),
plants = NULL
)
flatten_list(lst, delimiter="_")
的结果应该如下所示:
data.frame(
path = c("animals_lamas", "animals_lamas", "animals_primates_humans", "animals_primates_humans", "animals_primates_apes", "animals_primates_apes", "animals_primates_apes", "objects", "objects", "plants"),
value = c("brown", "white", "asia", "europe", "good", "fast", "angry", "expensive", "cheap", NA)
)
令我惊讶的是我无法使用 tidyr 或 data.tables 实现这一目标。我是否需要递归函数,或者是否有一些开箱即用的解决方案?赞赏!
编辑: akrun 提供的解决方案适用于原始数据。我意识到当元素在底层 NULL
时会出现问题,因此改写了问题。
EDIT2 我目前的解决方法是在应用 akrun 解决方案之前递归地用 NA
替换 NULL
,使用函数
可以通过 melt
进入 data.frame 然后 unite
键列
library(reshape2)
library(dplyr)
library(tidyr)
out2 <- melt(lst) %>%
unite(path, L1:L3, sep = "_", na.rm = TRUE) %>%
select(path, value)
-检查 OP 的输出
> all.equal(out, out2)
[1] TRUE
我们也可以用 unlist
和 stack
来自 base R
stack(unlist(lapply(lst, \(x) if(is.null(x)) NA_character_ else x)))[2:1]
可以对付NULL
的解决方案,基于rrapply
:
library(tidyverse)
library(rrapply)
rrapply(lst, f = \(x) if (is.null(x)) NA else x, how = "melt") %>%
unnest(value) %>% unite(path, L1:L3, na.rm = T)
#> # A tibble: 10 × 2
#> path value
#> <chr> <chr>
#> 1 animals_lamas brown
#> 2 animals_lamas white
#> 3 animals_primates_humans asia
#> 4 animals_primates_humans europe
#> 5 animals_primates_apes good
#> 6 animals_primates_apes fast
#> 7 animals_primates_apes angry
#> 8 objects expensive
#> 9 objects cheap
#> 10 plants <NA>