按名称从嵌套的R列表中删除元素

12

我有一个像这样的嵌套元素

> x <- list(a=list(from="me", id="xyz"), b=list(comment=list(list(message="blabla", id="abc"), list(message="humbug", id="jkl"))), id="123")
> str(x)
List of 3
 $ a :List of 2
  ..$ from: chr "me"
  ..$ id  : chr "xyz"
 $ b :List of 1
  ..$ comment:List of 2
  .. ..$ :List of 2
  .. .. ..$ message: chr "blabla"
  .. .. ..$ id     : chr "abc"
  .. ..$ :List of 2
  .. .. ..$ message: chr "humbug"
  .. .. ..$ id     : chr "jkl"
 $ id: chr "123"

如何删除列表中所有层级的名称为 id 的元素?即期望输出为

> str(x)
List of 2
 $ a:List of 1
  ..$ from: chr "me"
 $ b:List of 1
  ..$ comment:List of 2
  .. ..$ :List of 1
  .. .. ..$ message: chr "blabla"
  .. ..$ :List of 1
  .. .. ..$ message: chr "humbug"

使用rlist包的解决方案将特别受欢迎,但是任何有效的解决方案都可以。


你能展示一下预期的输出吗?(使用 dput 而不是 str - Sotos
预期输出是上面引号中的第二个块。 - Ricky
dput 是你的好朋友。 - Hack-R
3个回答

10
递归也是我完成它的方式:
# recursive function to remove name from all levels of list
stripname <- function(x, name) {
    thisdepth <- depth(x)
    if (thisdepth == 0) {
        return(x)
    } else if (length(nameIndex <- which(names(x) == name))) {
        x <- x[-nameIndex]
    }
    return(lapply(x, stripname, name))
}

# function to find depth of a list element
# see https://dev59.com/9WYr5IYBdhLWcg3wvslA
depth <- function(this, thisdepth=0){
    if (!is.list(this)) {
        return(thisdepth)
    } else{
        return(max(unlist(lapply(this,depth,thisdepth=thisdepth+1))))    
    }
}


str(stripname(x, "id"))
## List of 2
## $ a:List of 1
## ..$ from: chr "me"
## $ b:List of 1
## ..$ comment:List of 2
## .. ..$ :List of 1
## .. ..$ :List of 1
## .. .. ..$ message: chr "blabla"
## .. .. ..$ message: chr "humbug"

你可以把 if (length(nameIndex <- which(names(x) == name))) 替换成 if (any(nameIndex <- names(x) == name))) 我觉得这样会更好。 - Julien

3
尝试使用递归函数进行编程,像以下示例一样。
f <- function(i) 
  lapply(i, function(x) 
    if (is.list(x)) { 
      if(!is.null(names(x))) f(x[names(x)!="id"]) else f(x) 
    } else x
  )
str(f(x[names(x)!="id"]))
# List of 2
#  $ a:List of 1
#   ..$ from: chr "me"
#  $ b:List of 1
#   ..$ comment:List of 2
#   .. ..$ :List of 1
#   .. .. ..$ message: chr "blabla"
#   .. ..$ :List of 1
#   .. .. ..$ message: chr "humbug"

只有在列表的深度为2时,此方法才有效,就像示例中一样。如果存在更深层次的元素,则需要递归处理--也许可以使用rapply进行重写(但未成功)。 - Eric Lecoutre

2

这是一个老问题,但是可以使用rrapply()rrapply包中相当方便地完成(基于rapply()的重新访问):

rrapply::rrapply(
  x,                                        ## nested list
  condition = \(x, .xname) .xname != "id",  ## filter condition
  how = "prune"                             ## how to structure result
) |>
  str()

#> List of 2
#>  $ a:List of 1
#>   ..$ from: chr "me"
#>  $ b:List of 1
#>   ..$ comment:List of 2
#>   .. ..$ :List of 1
#>   .. .. ..$ message: chr "blabla"
#>   .. ..$ :List of 1
#>   .. .. ..$ message: chr "humbug"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接