我有一个输入数据结构,最终叶节点为空列表,父列表仅包含子列表。相关信息最终出现在列表属性中,我必须提取它。为此,我需要获取 all 列表元素的索引位置,并使用这些坐标来遍历列表。
{rrapply}
一直在为带有元素的列表工作,但我不知道如何获得没有非列表子元素的列表的位置。
下面是一个代表,显示了我得到
{rrapply}
得到的部分,以及它遗漏了什么,最后是一个非常老式的解决方案,我编写了代码来工作。所以我有一个解决方案,但我想看看我是否能让 {rrapply}
做到这一点,并理解为什么我不能让它做我想做的事。
# stackoverflow_list-element-position-vector.R
library(rrapply)
library(purrr)
# A sample list
lst <-
list(
list(),
list(
list(),
list(),
list()
),
list(a=1:3
, list()
)
)
# Misses all of the empty lists, just the sublist with the name "a":
rrapply(lst,
f = \(x, .xpos) .xpos,
how="melt") |>
pluck("value") |>
str()
#> List of 1
#> $ : int [1:2] 3 1
#;; From: https://stackoverflow.com/a/76124073/1022967
#;; Misses the positions of the intermediate nodes, which I need too.
#;; i.e., misses lists at position 2 and 3.
rrapply(lst
, classes = "list"
, condition = \(x) length(x) == 0
, f = \(x) NA
, how="recurse") |>
rrapply(f = \(x, .xpos) .xpos
, how="melt") |>
pluck("value") |>
str()
#> List of 6
#> $ : int 1
#> $ : int [1:2] 2 1
#> $ : int [1:2] 2 2
#> $ : int [1:2] 2 3
#> $ : int [1:2] 3 1
#> $ : int [1:2] 3 2
#;; Take a list, return flat list of all of the positions of list
#;; elements.
#;; Real old-school technique...
listEltPos <- function(llst) {
work_lst <-
list(list(coord_vec = integer(0), comp = llst))
output_lst <-
list()
while (TRUE) {
if (length(work_lst) == 0) break
# Pop off head of work_lst
e <-
pluck(work_lst, 1)
work_lst <-
work_lst[-1]
# If element isn't a list, nothing more to process
if (class(e$comp) != "list") next
# If here, it is a list. If length is 0, return
if (length(e$comp) == 0) next
# Otherwise, it has entries. Find relative coordinate of the entry
# and add that to the output list and make a list element with that
# coordinate and the corresponding subelement.
subElementPositions <-
seq(length(e$comp))
for (i in subElementPositions) {
# Append local pos to the overall coordinate vector
newPosVec <-
c(e$coord_vec, i)
sub_e <-
pluck(e$comp, i)
# Add current new pos to the output queue
output_lst <-
append(output_lst, list(newPosVec))
# Append subelements and their updated positions to the work queue
work_lst <-
append(work_lst, list(list(coord_vec=newPosVec, comp=sub_e)))
}
rm(i)
}
output_lst
}
#;; This is what I am hoping for
listEltPos(lst) |>
str()
#> List of 8
#> $ : int 1
#> $ : int 2
#> $ : int 3
#> $ : int [1:2] 2 1
#> $ : int [1:2] 2 2
#> $ : int [1:2] 2 3
#> $ : int [1:2] 3 1
#> $ : int [1:2] 3 2
创建于 2023-05-03 与 reprex v2.0.2
使用
rrapply()
的一种可能方法是使用 how = "recurse"
遍历嵌套列表,并通过将它们分配给全局变量(在函数范围之外)来跟踪所有遇到的 .xpos
值:
library(rrapply)
## initialize empty list
allpos <- list()
## walk nested list and append indices to `allpos`
invisible(
rrapply(
lst,
classes = c("list", "integer"),
how = "recurse",
f = \(x, .xpos) {
allpos <<- append(allpos, list(.xpos))
x
}
)
)
str(allpos)
#> List of 8
#> $ : int 1
#> $ : int 2
#> $ : int [1:2] 2 1
#> $ : int [1:2] 2 2
#> $ : int [1:2] 2 3
#> $ : int 3
#> $ : int [1:2] 3 1
#> $ : int [1:2] 3 2
注意:这对于非常大的列表来说效率不高,在这种情况下,最好提前确定
allpos
的大小,而不是迭代地将新值附加到列表中。
接受的答案正是我想要的。我在这里添加了我将该解决方案包装在一个函数中的方式,这样我就不会对
.GlobalEnv
进行任何更新。我还将一个参数更改为 classes
以执行 ANY
与 integer
,因为我可能有更多的整数(我没有在原始示例中列出)。
# A sample list, slightly different content, has an integer and character
# element.
lst <-
list(
list(),
list(
list(),
list()
),
list(a=1:3
, list()
, c= letters[1:4]
)
)
# From Joris solution here -- changes
getListNodePos <- function(llst) {
library(rrapply)
#;; https://stackoverflow.com/questions/8771942/how-can-i-reference-the-local-environment-within-a-function-in-r
locEnv <- environment()
## initialize empty list
allpos <- list()
## walk nested list and append indices to `allpos`
invisible(
rrapply(
llst,
classes = c("list", "ANY"),
how = "recurse",
f = \(x, .xpos) {
assign("allpos", append(allpos, list(.xpos)), envir = locEnv)
x
}
)
)
allpos
}
# Show the indexes
getListNodePos(lst) |>
str()
#> List of 8
#> $ : int 1
#> $ : int 2
#> $ : int [1:2] 2 1
#> $ : int [1:2] 2 2
#> $ : int 3
#> $ : int [1:2] 3 1
#> $ : int [1:2] 3 2
#> $ : int [1:2] 3 3
创建于 2023-05-04 与 reprex v2.0.2