在 lapply 函数中访问和保留列表名称
Posted
技术标签:
【中文标题】在 lapply 函数中访问和保留列表名称【英文标题】:Access and preserve list names in lapply function 【发布时间】:2012-03-17 04:34:38 【问题描述】:我需要访问 lapply 函数中的列表名称。我在网上找到了一些线程,据说我应该遍历列表的名称,以便能够在我的函数中获取每个列表元素名称:
> n = names(mylist)
> mynewlist = lapply(n, function(nameindex, mylist) return(mylist[[nameindex]]) , mylist)
> names(mynewlist)
NULL
> names(mynewlist) = n
问题是 mynewlist 丢失了原始 mylist 索引,我必须添加 last names() 分配来恢复它们。
有没有办法为 lapply 函数返回的每个元素指定一个明确的索引名称?或者另一种方法来确保 mynewlist 元素设置了正确的索引名称?如果 lapply 不以与 mylist 相同的顺序返回列表元素,我觉得 mynewlist 索引名称可能是错误的。
【问题讨论】:
我不断地回到这篇文章。按照下面的答案,您可以在加载 dplyr 后通过n <- names(mylist) %>% `names<-`(c(.))
直接将列表项指定为名称。
【参考方案1】:
我相信lapply
默认情况下会保留您正在迭代的任何内容的名称属性。当您将myList
的名称存储在n
中时,该向量不再具有任何“名称”。因此,如果您将其添加回 via,
names(n) <- names(myList)
和以前一样使用lapply
,应该会得到想要的结果。
编辑
今天早上我的大脑有点模糊。这是另一个可能更方便的选项:
sapply(n,FUN = ...,simplify = FALSE,USE.NAMES = TRUE)
我在摸索,很困惑lapply
没有USE.NAMES
参数,然后我实际上查看了sapply
的代码并意识到我很傻,这可能是一个更好的方法去吧。
【讨论】:
是的,这行得通。我仍然必须通过 n = names(myList) 创建“n”。两次调用 names(myList),一次创建 n,第二次设置 n 个属性。 你可以用names(n) <- n
替换第二个。
@RobertKubrick 查看我的编辑以获得更好的解决方案。检查sapply
的代码,看看这有多简单;它只是充当一个包装器,在事后添加名称。
@joran 我使用了 sapply 并且能够输出。但是你能解释一下为什么你说“然后我实际上查看了sapply
的代码并意识到我很傻”吗?那么为什么lapply
没有USE.NAMES
?
我一直在避免 sapply
因为不可预测的类型更改,但是,查看 sapply
源,如果 simplify
是 FALSE
似乎是安全的。例如。见***.com/questions/12339650/…谢谢!【参考方案2】:
setNames
函数在这里是一个有用的快捷方式
mylist <- list(a = TRUE, foo = LETTERS[1:3], baz = 1:5)
n <- names(mylist)
mynewlist <- lapply(setNames(n, n), function(nameindex) mylist[[nameindex]])
保留名称
> mynewlist
$a
[1] TRUE
$foo
[1] "A" "B" "C"
$baz
[1] 1 2 3 4 5
【讨论】:
如何将“mylist”传递给函数? @rmf 严格来说,你没有通过mylist
。它在lapply
中的匿名函数内部被引用,但该引用是在封闭环境中。【参考方案3】:
以 joran 的回答为基础,并加以精确:
sapply(USE.NAMES=T)
包装器确实会将您正在迭代的向量的值设置为最终结果的名称(而不是其名称属性,如 lapply),但前提是这些是字符。
因此,传递索引将无济于事。如果你想用sapply
传递索引,你需要使用一些(丑陋的)强制转换:
sapply(as.character(c(1,11)), function(i) TEST[[as.numeric(i)]], USE.NAMES = TRUE)
在这种情况下,更简洁的解决方案是直接设置和使用原始对象的名称。以下是详尽的解决方案列表:
TEST <- as.list(LETTERS[1:12])
### lapply ##
## Not working because no name attribute
lapply(c(1,11), function(i) TEST[[i]])
## working but cumbersome
index <- c(1,11)
names(index) <- index
lapply(index, function(i) TEST[[i]])
### sapply ##
## Not working because vector elements are not strings
sapply(c(1,11), function(i) TEST[[i]], simplify = F)
## Working with the casting trick
sapply(as.character(c(1,11)), function(i) TEST[[as.numeric(i)]], simplify = F)
## Cleaner, using names with sapply:
names(TEST) <- LETTERS[26:15]
sapply(names(TEST)[c(1,11)], function(name) TEST[[name]], simplify = F)
【讨论】:
【参考方案4】:purrr
包中的imap()
非常适合您的问题。
library(purrr)
mylist <- list(foo1=1:10,foo2=11:20)
imap(mylist, function(x, y) mean(x)) ## x is the value, y is the name
或者您可以使用更紧凑的 imap 版本:
imap(mylist, ~ mean(.x))
请注意,您可以根据所需的矢量类型使用 imap_xxx 的变体:
imap_dbl(mylist, ~ mean(.x)) ## will return a named numeric vector.
【讨论】:
【参考方案5】:你有没有从包plyr
查看llply()
?
它完全符合您的要求。 对于列表的每个元素,应用函数,将结果保存为列表。 llply 等价于 lapply,只是它会保留标签并且可以显示进度条。来自?llply
mylist <- list(foo1=1:10,foo2=11:20)
>names(mylist)
[1] "foo1" "foo2"
newlist<- llply(mylist, function(x) mean(x))
>names(newlist)
[1] "foo1" "foo2"
【讨论】:
嗯。这看起来正是lapply
所做的。参见例如lapply(mylist, mean)
和llply(names(mylist), function(x) mean(mylist[[x]]))
。任何想法“保留标签”是什么意思?
我认为mlply
会这样做【参考方案6】:
同样基于@joran 的回答,您可以编写一个保留对象属性的包装函数,如下所示:
lapply_preserve_names <- function(list, fun)
lapply(seq_along(list), function(i)
obj = list[i]
names(obj) = names(list)[i]
fun(obj)
)
那么不要使用 lapply,只需使用 lapply_preserve_names(your_list, function)
【讨论】:
以上是关于在 lapply 函数中访问和保留列表名称的主要内容,如果未能解决你的问题,请参考以下文章