如何仅在嵌套列表中在最深层次上运行函数?

Tho*_*ing 8 r list

给定一个嵌套列表,例如如下

lst <- list(
    1,
    list(list(c(4, 5, 4)), list(c(6, 7))),
    list(c(2, 3, 3)),
    list(list(c(5, 5, 6)), list(c(7, 7, 7)))
)

> str(lst)
List of 4
 $ : num 1
 $ :List of 2
  ..$ :List of 1
  .. ..$ : num [1:3] 4 5 4
  ..$ :List of 1
  .. ..$ : num [1:2] 6 7
 $ :List of 1
  ..$ : num [1:3] 2 3 3
 $ :List of 2
  ..$ :List of 1
  .. ..$ : num [1:3] 5 5 6
  ..$ :List of 1
  .. ..$ : num [1:3] 7 7 7
Run Code Online (Sandbox Code Playgroud)

比方说,最深切的级别为3,如向量的深处4 5 46 75 5 67 7 7lst

我想知道是否有一种方法可以只在那些最深层次上运行某个功能,而其他层次不受影响。例如,如果函数是unique,那么我的预期输出是

lstout <- list(
    1,
    list(list(c(4, 5)),list(c(6,7))),
    list(c(2, 3, 3)),
    list(list(c(5, 6)), list(7))
)

> str(lstout)
List of 4
 $ : num 1
 $ :List of 2
  ..$ :List of 1
  .. ..$ : num [1:2] 4 5
  ..$ :List of 1
  .. ..$ : num [1:2] 6 7
 $ :List of 1
  ..$ : num [1:3] 2 3 3
 $ :List of 2
  ..$ :List of 1
  .. ..$ : num [1:2] 5 6
  ..$ :List of 1
  .. ..$ : num 7
Run Code Online (Sandbox Code Playgroud)

似乎rapply不能只在最深层次上有选择地运行该功能。我不知道怎么做。

任何基本的 R想法或解决方案将不胜感激!

G. *_*eck 6

我们可以递归下降lst以找到最大深度,然后使用它再次递归下降,unique仅在最大深度处应用。不使用任何包。

maxDepth <- function(x, depth = 0) {
   if (is.list(x)) max(sapply(x, maxDepth, depth+1))
   else depth
}

lstUnique <- function(x, depth = maxDepth(x)) {
  if (depth == 0) unique(x)
  else if (is.list(x)) lapply(x, lstUnique, depth-1)
  else x
}

lstUnique(lst)
Run Code Online (Sandbox Code Playgroud)

使用rapply变化

上面的一个变体是递归地向每个叶子添加一个等于其深度的类。然后我们可以使用rapply3次。首先使用rapply提取类并取最大值以找到最大深度。第二个用途rapply是仅应用于unique具有最大深度类的节点。第三,删除unique由于节点未达到最大深度而未被删除的任何剩余类。(第三个rapply,即下面的最后一行代码,如果可以为我们添加的类留下一些叶子就可以省略。)

addDepth <- function(x, depth = 0) {
  if (is.list(x)) lapply(x, addDepth, depth+1)
  else structure(x, class = format(depth))
}
lst2 <- addDepth(lst)

mx <- max(as.numeric(rapply(lst2, class))) # max depth
lst3 <- rapply(lst2, unique, classes = format(mx), how = "replace")
rapply(lst3, as.vector, how = "replace")
Run Code Online (Sandbox Code Playgroud)

rapply 的注意事项

请注意,如果您交替希望在所有叶子上运行 unique 而不仅仅是在最大深度叶子上运行,那么rapply在基础 R 中将起作用。

rapply(lst, unique, how = "replace")
Run Code Online (Sandbox Code Playgroud)

数据树

此替代方法确实需要使用包。首先,我们创建一个 data.tree dt,然后遍历它,将唯一的应用于满足 filterFun 的节点。

library(data.tree)

dt <- as.Node(lst)
dt$Do(function(x) x$"1" <- unique(x$"1"), 
  filterFun = function(x) x$level == dt$height)
print(dt, "1")
Run Code Online (Sandbox Code Playgroud)

拉皮

rrapply 包提供了对 rapply 的增强,它也可以传递一个长度等于深度的位置向量,因此我们可以首先使用它来计算最大深度 mx,然后再次仅在该深度应用唯一。(更新rrapply了使用 how = "unlist" 的调用,而不是根据评论中的建议在之后应用 unlist。)

library(rrapply)

mx <- max(rrapply(lst, f = function(x, .xpos) length(.xpos), how = "unlist"))
uniq_mx <- function(x, .xpos) if (length(.xpos) == mx) unique(x) else x
rrapply(lst, is.numeric, uniq_mx)
Run Code Online (Sandbox Code Playgroud)