R基于列表对象中的条件过滤列表

时间:2019-08-15 14:36:18

标签: r list filter tidyverse

这是一个琐碎的问题,但是我很困惑。如何根据数据帧的长度过滤列表?该列表是嵌套的-意味着存在不同长度的数据帧列表的列表。这是一个例子。我想对列表进行过滤或子集化,以仅包括长度为 n 的对象,例如3。

这是一个例子,也是我目前的做法。

library(tidyverse)

# list of list with arbitrary lengths 

star.wars_ls <- list(starwars[1:5], 
                     list(starwars[1:8], starwars[4:6]), 
                     starwars[1:2], 
                     list(starwars[1:7], starwars[2:6]), 
                     starwars[1:3])


# I want to filter the list by dataframes that are 3 variables long (i.e. length(df == 3).

# Here is my attempt, I'm stuck at how to obtain 
# the number of varibles in each dataframe and then filter by it. 

map(star.wars_ls, function(x){
    map(x, function(x){ ## Incorrectly returns 20 for all 
        length(y)
    })

})

3 个答案:

答案 0 :(得分:1)

我们可以做到

  map(star.wars_ls, ~ if(is.data.frame(.x)) .x[length(.x) == 3] else map(.x, ~ .x[length(.x) == 3]))

答案 1 :(得分:1)

您应该能够检查star.wars_ls中的项目是列表还是数据框。然后,检查每个项目中的列数。尝试使用:

library(tidyverse)

# list of list with arbitrary lengths 

star.wars_ls <- list(starwars[1:5], 
                     list(starwars[1:8], starwars[4:6]), 
                     starwars[1:2], 
                     list(starwars[1:7], starwars[2:6]), 
                     starwars[1:3])


# I want to filter the list by dataframes that are 3 variables long (i.e. length(df == 3).

datacols <- map(star.wars_ls, function(X) {
  if (is.data.frame(X) == T) {
    ncol(X) } 
    else {
      map(X, function(Y) {
        ncol(Y)
      })
      }
    }
)

# > datacols
# [[1]]
# [1] 5
# 
# [[2]]
# [[2]][[1]]
# [1] 8
# 
# [[2]][[2]]
# [1] 3
# 
# 
# [[3]]
# [1] 2
# 
# [[4]]
# [[4]][[1]]
# [1] 7
# 
# [[4]][[2]]
# [1] 5
# 
# 
# [[5]]
# [1] 3

这只会给您列表中每个数据帧的长度(列数)。要获取索引(我相信有一种更有效的方法可以做到这一点-也许其他人可以提供帮助):

indexlist <- c()
for (i in 1:length(datacols)) {
  if (length(datacols[[i]]) == 1) {
    if (datacols[[i]][1] == 3) {
      index <- i 
      indexlist <- c(indexlist, as.character(index))
    }
  } else {
    for (j in 1:length(datacols[[i]])) {
      if (datacols[[i]][[j]][1] == 3) {
        index <- str_c(i, ",", j)
        indexlist <- c(indexlist, index)
      }
    }
  }
}

# > indexlist
# [1] "2,2" "5"  

答案 2 :(得分:1)

您可以使用递归。列表有多深嵌套都没关系:

ff = function(x)map(x,~if(is.data.frame(.x)){if(length(.x)==3) .x} else ff(.x))
ff(star.wars_ls)
相关问题