【问题标题】:how to remove elements in list of lists of nested lists?如何删除嵌套列表列表中的元素?
【发布时间】:2019-07-13 14:58:28
【问题描述】:

我该怎么走

x <- list(p1 = list(type='A',score=list(c1=10,c2=8,c3=data.frame(a=1, b=3, c=5))),
       p2 = list(type='B',score=list(c1=9,c2=9,c3=data.frame(a=2, b=2))),
       p3 = list(type='B',score=list(c1=9,c2=7,c3=data.frame(a=2, b=2))))

到没有作为数据框的“c3”元素的列表?

最好以tidyverse 友好的方式或我可以放在管道中间的方式。

我已经尝试过 list.remove、nested lapply、rapply、Filter,但似乎无法让它们工作......而且我不想取消列出我的嵌套列表结构。

(编辑:抱歉,我在原始问题中的示例数据中有错字(见下文),但如果您的解决方案在这两种情况下都有效!)

x <- list(p1 = list(type='A',score=list(c1=10,c2=8,c3=data.frame(a=1, b=3, c=5))),
       p2 = list(type='B',score=list(c1=9,c2=9,c3=data.frame(a=2, b=2)),
       p3 = list(type='B',score=list(c1=9,c2=7,c3=data.frame(a=2, b=2)))))

【问题讨论】:

  • 您是否打算让 p3 成为 p2 内部的元素而不是 p 级别的元素?
  • 哎呀,你说得对,我的意思是 p1 p2 p3 处于同一级别,但无论哪种方式,我更喜欢适用于任何复杂嵌套的东西。

标签: r list nested


【解决方案1】:

这是使用modify_depth 的正确场景,它用作modify 链访问深层嵌套列表的快捷方式。在这个问题上,modify 比 map 有优势,因为它将保留输入的类型,而不是将所有内容强制转换为列表,如果列表结构中有向量元素,这可能是相关的。

使用您给定的输入(内部有一个p3 元素,而不是与p2 在同一级别),第二和第三级别的数据框元素是discarded,如下所示。为了搜索嵌套列表的所有级别,我们可以设置一个while 循环来遍历各个级别,同时丢弃数据帧。我们需要.ragged = TRUE 来处理列表深度的错误。此版本自下而上搜索,但您也可以将其更改为自上而下搜索。

library(tidyverse)
x <- list(
  p1 = list(type = "A", score = list(c1 = 10, c2 = 8, c3 = data.frame(a = 1, b = 3, c = 5))),
  p2 = list(
    type = "B", score = list(c1 = 9, c2 = 9, c3 = data.frame(a = 2, b = 2)),
    p3 = list(type = "B", score = list(c1 = 9, c2 = 7, c3 = data.frame(a = 2, b = 2)))
  )
)

remove_dataframes <- function(input_list) {
  current_list <- input_list
  current_depth <- vec_depth(current_list)
  # current_depth <- max_depth
  while (current_depth > 1) {
    current_list <- modify_depth(
      .x = current_list,
      .depth = current_depth,
      .f = ~ discard(., is.data.frame),
      .ragged = TRUE
    )
  current_depth <- current_depth - 1
  }
  return(current_list)
}

x %>%
  remove_dataframes %>%
  glimpse
#> List of 2
#>  $ p1:List of 2
#>   ..$ type : chr "A"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 10
#>   .. ..$ c2: num 8
#>  $ p2:List of 3
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 9
#>   ..$ p3   :List of 2
#>   .. ..$ type : chr "B"
#>   .. ..$ score:List of 2

由reprex package (v0.2.1) 于 2019-02-20 创建

【讨论】:

  • 你是指最低p3级别的那个还是别的什么?
  • 是的,我正在尝试摆脱所有 c3 data.frames。我尝试将您的代码用于 p1 p2 p3 处于同一级别的数据集,但在这两种情况下,我都得到“范围 [1] 中的错误:'closure' 类型的对象不是子集”
  • 已更新以解决多层问题。
  • 由于某种原因,我仍然收到“范围 [1] 中的错误:'closure' 类型的对象不是子集”。我知道您使用的是 reprex,所以这很奇怪...感谢您向我展示 purrr 函数 modify、modify_depth 和 discard
【解决方案2】:

您可以编写自己的函数来执行此操作:

check = function(x,name){
  m = names(x)%in% name
  x = if(any(m)) x[!m] else x
  if(is.list(x)) sapply(x,check,name)
  else x
}

dput(check(x,'c3'))
list(p1 = list(type = "A", score = list(c1 = 10, c2 = 8)), p2 = list(
    type = "B", score = list(c1 = 9, c2 = 9), p3 = list(type = "B", 
        score = list(c1 = 9, c2 = 7))))

这也是 vecotized,因为它可以丢弃所有你需要的东西。例如尝试check(x,c('c1','c3'))

【讨论】:

  • 酷,我应该在编程课上多练习递归!我改进了您的答案,以便维护列表结构,而标准是 is.data.frame。 removeDataFramesFromList
【解决方案3】:

这是在rrapply-package 中使用rrapply() 的另一种替代方法,适用于任意级别的嵌套:

library(rrapply)

x1 <- rrapply(x, condition = function(x, .xparents) !any(.xparents == "c3"), how = "prune")
str(x1)  
#> List of 3
#>  $ p1:List of 2
#>   ..$ type : chr "A"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 10
#>   .. ..$ c2: num 8
#>  $ p2:List of 2
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 9
#>  $ p3:List of 2
#>   ..$ type : chr "B"
#>   ..$ score:List of 2
#>   .. ..$ c1: num 9
#>   .. ..$ c2: num 7

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-03
    • 2017-03-02
    • 2021-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    相关资源
    最近更新 更多