R 使用unlist递归地简化列表

R 使用unlist递归地简化列表,r,list,purrr,simplify,R,List,Purrr,Simplify,考虑这样一个案例: 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")) 我曾涉猎过rapply,但它对不是列表本身的列表成员有明确的作用,因此写了以下内容: library(magritt

考虑这样一个案例:

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"))
我曾涉猎过rapply,但它对不是列表本身的列表成员有明确的作用,因此写了以下内容:

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)
      })
}

即使对于我正在处理的深度列表,这似乎也能起到预期的作用,但在示例中,以前是向量的元素(如c.d和d)现在被转换为列表,这与目的背道而驰。。。有进一步的见解吗?

我不了解magrittr的内容,但创建递归函数很容易:

foo <- function(L) lapply(L, function(x) {
  if (is.list(x) && length(x) > 1) return(foo(x))
  if (is.list(x) && length(x) == 1) x[[1]] else x
  })
foo(test_list)

#$`a`
# [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
#
#$b
#[1] "a"
#
#$c
#$c$`c.1`
#[1] "b"
#
#$c$c.2
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
#
#$c$c.3
#$c$c.3[[1]]
#[1] "c"
#
#$c$c.3[[2]]
#[1] "d"

如果这引发了一个关于C堆栈使用的错误,那么您就有了嵌套很深的列表。您当时不能使用递归,这将使这成为一个具有挑战性的问题。如果可能的话,我会修改这个列表的创建。或者你可以尝试。

在purrr的github存储库的帮助下,我解决了这个问题:使用当前开发者版本的purrr,可以通过remotes::install_github'tidyverse/purrr'安装,问题中的purrr依赖代码按照预期工作,不再列出向量。因此,该代码应作为问题的答案,并在2018/19年新年后与CRAN-borne软件包一起充分发挥功能。

谢谢。这在本质上就是我自己的函数试图做的事情,但在更深层的列表中遇到同样的C堆栈问题时失败了。请参阅我答案的最后一部分。我想你可能有xy问题。
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)
}
foo <- function(L) lapply(L, function(x) {
  if (is.list(x) && length(x) > 1) return(foo(x))
  if (is.list(x) && length(x) == 1) x[[1]] else x
  })
foo(test_list)

#$`a`
# [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
#
#$b
#[1] "a"
#
#$c
#$c$`c.1`
#[1] "b"
#
#$c$c.2
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
#
#$c$c.3
#$c$c.3[[1]]
#[1] "c"
#
#$c$c.3[[2]]
#[1] "d"