2016-03-07 57 views
3

编辑:我改写这个问题,因为我有,也许可以更好地一起回答了两个相关的问题...R:如何从属性的嵌套列表中设置名称


我有一些大嵌套list s几乎相同的结构,没有名称。 list的所有项目都有attr ibutes,我想在list的所有级别中指定这些名称。此外,我想放弃一个不必要的列表级别。

所以这个:

before <- list(list("value_1"), list(list("value_2a"), list("value_2b")), list(list("value_3a"), list("value_3b"), list("value_3c")), list("value_4")) 
for(i in 1:4) attr(before[[i]], "tag") <- paste0("tag_", i) 
attr(before[[2]][[1]], "code") <- "code_2a" 
attr(before[[2]][[2]], "code") <- "code_2b" 
attr(before[[3]][[1]], "code") <- "code_3a" 
attr(before[[3]][[2]], "code") <- "code_3b" 
attr(before[[3]][[3]], "code") <- "code_3c" 
str(before) 
## List of 4 
## $ :List of 1 
## ..$ : chr "value_1" 
## ..- attr(*, "tag")= chr "tag_1" 
## $ :List of 2 
## ..$ :List of 1 
## .. ..$ : chr "value_2a" 
## .. ..- attr(*, "code")= chr "code_2a" 
## ..$ :List of 1 
## .. ..$ : chr "value_2b" 
## .. ..- attr(*, "code")= chr "code_2b" 
## ..- attr(*, "tag")= chr "tag_2" 
## $ :List of 3 
## ..$ :List of 1 
## .. ..$ : chr "value_3a" 
## .. ..- attr(*, "code")= chr "code_3a" 
## ..$ :List of 1 
## .. ..$ : chr "value_3b" 
## .. ..- attr(*, "code")= chr "code_3b" 
## ..$ :List of 1 
## .. ..$ : chr "value_3c" 
## .. ..- attr(*, "code")= chr "code_3c" 
## ..- attr(*, "tag")= chr "tag_3" 
## $ :List of 1 
## ..$ : chr "value_4" 
## ..- attr(*, "tag")= chr "tag_4" 

(注:第一级列表项有一个 “标签” -attribute,二级项目有一个 “代码” -attribute。)

应该是这样:

after <- list(tag_1="value_1", tag_2=list(code_2a="value_2a", code_2b="value_2b"), tag_3=list(code_3a="value_3a", code_3b="value_3b", code_3c="value_3c"), tag_4="value_4") 
str(after) 
## List of 4 
## $ tag_1: chr "value_1" 
## $ tag_2:List of 2 
## ..$ code_2a: chr "value_2a" 
## ..$ code_2b: chr "value_2b" 
## $ tag_3:List of 3 
## ..$ code_3a: chr "value_3a" 
## ..$ code_3b: chr "value_3b" 
## ..$ code_3c: chr "value_3c" 
## $ tag_4: chr "value_4" 

由于列表很大,我想避免for循环,以获得更好的性能。

+1

'help(“rapply”)' – Roland

+0

谢谢罗兰。我完全忽视了'rapply'。现在我可以使用列表中的值:'test < - rapply(before,function(x)paste(x,“foo”),how =“list”)'但是如何使用属性?你能再给我一个提示吗? –

回答

0

您可以通过递归遍历列表轻松完成此操作。试试这个:

setListNames <- function(mylist){ 
    # Base case: if we have a nonlist object, set name to its attribute 
    if(!is.list(mylist)){ 
    names(mylist) = attr(mylist, 'code') 
    return(mylist) 
    } 

    # lapply through all sublists and recursively call 
    mylist = lapply(mylist, setListNames) 

    # Return named list 
    return(mylist) 
} 

# Test run 
before_named = setListNames(before) 
# Check it worked 
print(names(before_named[[2]][[1]][[1]])) 
+0

正如我刚刚添加到问题,我想避免循环。但是,你是否尝试过你的代码? before和before_named在我的测试中是相等的。 –

+0

'相同(before,before_named)'给我'FALSE'并且名字确实存在。这些清单是如何构建的?为什么不在列表创建之前设置名称? – by0

+0

我已经编辑了使用'lapply'而不是for循环的答案,但我怀疑这会大大提高性能。 – by0

0

Got it!三个步骤,但完美的作品。

# the ugly list 
ugly_list <- list(list("value_1"), list(list("value_2a"), list("value_2b")), list(list("value_3a"), list("value_3b"), list("value_3c")), list("value_4")) 
for(i in 1:4) attr(ugly_list[[i]], "tag") <- paste0("tag_", i) 
attr(ugly_list[[2]][[1]], "code") <- "code_2a" 
attr(ugly_list[[2]][[2]], "code") <- "code_2b" 
attr(ugly_list[[3]][[1]], "code") <- "code_3a" 
attr(ugly_list[[3]][[2]], "code") <- "code_3b" 
attr(ugly_list[[3]][[3]], "code") <- "code_3c" 

# set names for 1st level 
level_1_named <- setNames(ugly_list, sapply(ugly_list, function(x) attributes(x)$tag)) 

# set names for 2nd level 
level_2_named <- lapply(level_1_named, function(x) lapply(x, function(y) setNames(y, attributes(y)$code))) 

# clean list 
clean_list <- lapply(level_2_named, function(x) unlist(x, recursive=FALSE)) 

感谢您的尝试。 :-)

相关问题