Рассмотрим случай, подобный следующему:
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
-членах, которые NOT перечисляют себя, поэтомунаписал следующее:
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
-хорошость, выполняет итерацию по глубине списка и NEARLY делает то, что я хочу:
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
, что побеждает цель ... дальнейшее понимание?