从嵌套列表中提取数据帧

Wil*_*ill 6 r

我有一个嵌套的列表列表,其中包含一些数据框。但是,数据框可以出现在列表中的任何级别。我想要最终得到的是一个平面列表,即只有一个级别,其中每个元素只是数据帧,所有其他内容都被丢弃。

我已经为此提出了一个解决方案,但它看起来非常笨重,我确信应该有一个更优雅的解决方案。

重要的是,我正在寻找基本 R 中的一些东西,它可以提取嵌套列表内任何级别的数据帧。我尝试过unlist()并涉足rapply()但不知何故没有找到令人满意的解决方案。

示例代码如下:示例列表,我实际上想要实现的目标,以及我自己不太满意的解决方案。谢谢你的帮助!

# extract dfs from list

# example of multi-level list with some dfs in it
# note, dfs could be nested at any level
problem1 <- list(x1 = 1,
              x2 = list(
                x3 = "dog",
                x4 = data.frame(cats = c(1, 2),
                               pigs = c(3, 4))
              ),
              x5 = data.frame(sheep = c(1,2,3),
                             goats = c(4,5,6)),
              x6 = list(a = 2,
                       b = "c"),
              x7 = head(cars,5))

# want to end up with flat list like this (names format is optional)
result1 <- list(x2.x4 = data.frame(cats = c(1, 2),
                                   pigs = c(3, 4)),
                x5 = data.frame(sheep = c(1,2,3),
                                goats = c(4,5,6)),
                x7 = head(cars,5))

# my solution (not very satisfactory)

exit_loop <- FALSE
while(exit_loop == FALSE){
  # find dfs (logical)
  idfs <- sapply(problem1, is.data.frame)
  # check if all data frames
  exit_loop <- all(idfs)
  # remove anything not df or list
  problem1 <- problem1[idfs | sapply(problem1, is.list)]
  # find dfs again (logical)
  idfs <- sapply(problem1, is.data.frame)
  # unlist only the non-df part
  problem1 <- c(problem1[idfs], unlist(problem1[!idfs], recursive = FALSE))

}

Run Code Online (Sandbox Code Playgroud)

eko*_*oam 5

Maybe consider a simple recursive function like this

find_df <- function(x) {
  if (is.data.frame(x))
    return(list(x))
  if (!is.list(x))
    return(NULL)
  unlist(lapply(x, find_df), FALSE)
}
Run Code Online (Sandbox Code Playgroud)

Results

> find_df(problem1)
$x2.x4
  cats pigs
1    1    3
2    2    4

$x5
  sheep goats
1     1     4
2     2     5
3     3     6

$x7
  speed dist
1     4    2
2     4   10
3     7    4
4     7   22
5     8   16
Run Code Online (Sandbox Code Playgroud)