递归地从列表的列表中提取元素

3

我有以下类型的嵌套列表:

现状

mylist <- list(
    "A",
    list(
        "B1",
        list(
            "C_B1",
            "w"
        ),
        "B2",
        list(
            "C_B2",
            "x"
        ),
        "B3",
        list(
            "C_B3_1",
            list(
                "D_B3_1",
                "y"
            ),
            "C_B3_2",
            list(
                 "D_B3_2",
                 "z"
            )
        )
    )
)

这里列表中的名称实际上是存储为一个模式,该模式似乎是由名称后跟列表或单个元素组成的。该模式可以扩展任意次数,并且在每个列表中,该模式可以重复。

这些数据来自于NLP包中的树形结构。以下是该结构的示例:https://dl.dropboxusercontent.com/u/61803503/Errors/sample.R

期望输出

list(
    A = list(
        B1 = list(
            C_B1 = "w"
        ),
        B2 = list(
            C_B2 = "x"
        ),
        B3 = list(
            C_B3_1 = list(
                D_B3_1 = "y"
            ),
            C_B3_2 = list(
                 D_B3_2 = "z"
            )
        )
    )
)

## $A
## $A$B1
## $A$B1$C_B1
## [1] "w"
## 
## 
## $A$B2
## $A$B2$C_B2
## [1] "x"
## 
## 
## $A$B3
## $A$B3$C_B3_1
## $A$B3$C_B3_1$D_B3_1
## [1] "y"
## 
## 
## $A$B3$C_B3_2
## $A$B3$C_B3_2$D_B3_2
## [1] "z"
注意,嵌套程度不能保证,只有一个列表和每个列表的第一个元素是该列表中值(第二个元素)的名称。

3
你是如何首次获取这种结构的数据的? - Dason
嗯...你在双井号(:-))后列出的内容不清楚。你怎么知道你已经深入到实际数据(例如x、y、z)了呢?如果你能解释一下,那么使用assign或臭名昭著的eval(parse(paste0(names(df[[1]])[1],'<- ', df[[1]][[1]][1]))设置进行一些黑客攻击可能会有所帮助。 - Carl Witthoft
@Dason:http://stackoverflow.com/questions/28133394/extract-elements-from-nlp-tree?noredirect=1#comment44639944_28133394 这是来自NLP包的树形结构。 - Tyler Rinker
名称总是第一个元素吗?还是列表总是遵循名称1、数据1、名称2、数据2等模式? - Dason
@Dason 第二个。我发现我的描述不够准确。我会修改。 - Tyler Rinker
显示剩余2条评论
2个回答

1
我依赖于问题陈述中的“这里列表的名称实际上存储为每个列表的第一个元素。”并使用符合此规则的已更正示例。
mylist <- 
list( "A",
    list("B1",
        list("C_B1",
            "w"),
        list("B2",
            list( "C_B2",
                "x")),
        list("B3",
            list( "C_B3_1",
                list( "D_B3_1",
                    "y"),
                list("C_B3_2",
                    list("D_B3_2",
                        "z")
                )
            )
        )
    )
)

递归遍历列表的一种方法是编写如下递归函数:

firstEltAsName  <-  function(x){
    # if x is not a list, return x
    if(!inherits(x,'list'))
        return(x)
    # recurse on everythin but the first element
    out  <-  lapply(x[-1],firstEltAsName)
    # take the names from the first element of the remaining elements.
    names(out)  <-  sapply(x[-1],`[`,1)
    # use the first element as the name 
    return(out)
}
firstEltAsName( mylist)

如果您的示例确实正确,则您想要:
OddEltsAsNames  <-  function(x){
    stopifnot(length(x)%%2 == 0)

    # recurse on the even elements
    out  <-  lapply(x[which(seq_along(x)%%2 == 0)],firstEltAsName)

    # take the names from the even elements 
    names(out)  <-  unlist( x[which(seq_along(x)%%2 == 1)] )

    return(out)
}
OddEltsAsNames( mylist)

这不是完全正确的。请注意,它并不总是一个包含两个元素的列表。它具有模式list(name1, out1, name2, out2, name3, out3)。 - Dason
OP指出:“这里列表的名称实际上存储在每个列表的第一个元素中。”我依赖于一个(上面提供的)实际符合此说明的示例。 - Jthorpe
1
是的,他的示例数据和问题陈述中的内容并不完全匹配。 - Dason
@Dason 如果您能让它更清晰,我们将感激您的编辑。 - Tyler Rinker
在你的例子中,第一个嵌套列表有6个元素;奇数元素是名称,偶数元素是列表。这与语句“这里列表的名称实际上存储在每个列表的第一个元素中。”不符,因为名称“B1”,“B2”和“B3”不符合此模式。 - Jthorpe

1
有点丑但是能用:

library(magrittr)

stackUp = function(lst)
{
    cond = lst %>% sapply(is.list) %>% any

    if(!cond) return(setNames(list(lst[[2]]), lst[[1]]))

    index = seq(1, length(lst), 2)

    index %>%
        lapply(function(u) stackUp(lst[[u+1]]))  %>%
        setNames(sapply(index, function(u) lst[[u]]))
}

> stackUp(mylist)
#$A
#$A$B1
#$A$B1$C_B1
#[1] "w"


#$A$B2
#$A$B2$C_B2
#[1] "x"


#$A$B3
#$A$B3$C_B3_1
#$A$B3$C_B3_1$D_B3_1
#[1] "y"


#$A$B3$C_B3_2
#$A$B3$C_B3_2$D_B3_2
#[1] "z"

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