Рассмотрим такой случай:
xml_list <- list(
a = "7",
b = list("8"),
c = list(
c.a = "7",
c.b = list("8"),
c.c = list("9", "10"),
c.d = c("11", "12", "13")),
d = c("a", "b", "c"))
то, что я ищу, - это способ рекурсивного упрощения этой конструкции, чтобы unlist
вызывался для любого list
длины 1. Ожидаемый результат для приведенного выше примера будет выглядеть так:
list(
a = "7",
b = "8",
c = list(
c.a = "7",
c.b = "8",
c.c = list("9", "10"),
c.d = c("11", "12", "13")),
d = c("a", "b", "c"))
Я баловался с rapply
, но это явно работает с list
-членами, которые сами НЕ являются списками, поэтому написал следующее:
library(magrittr)
clean_up_list <- function(xml_list){
xml_list %>%
lapply(
function(x){
if(is.list(x)){
if(length(x) == 1){
x %<>%
unlist()
} else {
x %<>%
clean_up_list()
}
}
return(x)
})
}
Это, однако, я даже проверить не могу, как Error: C stack usage 7969588 is too close to the limit
(по крайней мере, на списках, которые я окончательно хочу обработать).
Копнув глубже (и обдумав ответ @Roland), я придумал решение, которое использует purrr
-добро, обратно перебирает глубину списка и ПОЧТИ делает то, что я хочу:
clean_up_list <- function(xml_list)
{
list_depth <- xml_list %>%
purrr::vec_depth()
for(dl in rev(sequence(list_depth)))
{
xml_list %<>%
purrr::modify_depth(
.depth = dl,
.ragged = TRUE,
.f = function(x)
{
if(is.list(x) && length(x) == 1 && length(x[[1]]) == 1)
{
unlist(x, use.names = FALSE)
} else {
x
}
})
}
return(xml_list)
}
Кажется, это работает так, как предполагалось, даже для списков глубины, с которыми я имею дело, НО элементы, которые раньше были векторами (например, c.d
и d
в примере), теперь преобразуются в lists
, что противоречит цели. ... какие-либо дополнительные сведения?