在 lapplication 函数中访问和保留列表名

我需要访问 lapplication 函数中的列表名称。我在网上找到了一些线程,据说我应该遍历列表的名称,以便能够在函数中获取每个列表元素的名称:

> n = names(mylist)
> mynewlist = lapply(n, function(nameindex, mylist) { return(mylist[[nameindex]]) }, mylist)
> names(mynewlist)
NULL
> names(mynewlist) = n

问题是 mynewlist 丢失了原始的 mylist 索引,我必须添加 last name ()赋值来恢复它们。

有没有一种方法可以为 lapplication 函数返回的每个元素提供一个显式的索引名称?或者另一种方法来确保 mynewlist 元素具有正确的索引名称集?我觉得如果 lapplication 不按照与 mylist 相同的顺序返回 list 元素,那么 mynewlist 索引名可能是错误的。

63785 次浏览

I believe that lapply by default keeps the names attribute of whatever you are iterating over. When you store the names of myList in n, that vector no longer has any "names". So if you add that back in via,

names(n) <- names(myList)

如果像以前一样使用 lapply,就会得到预期的结果。

剪辑

今天早上我的脑子有点糊涂。这里还有另一个,也许更方便的选择:

sapply(n,FUN = ...,simplify = FALSE,USE.NAMES = TRUE)

我一直在摸索,困惑于 lapply没有 USE.NAMES参数,然后我看了看 sapply的代码,意识到我是在犯傻,这可能是一个更好的方法。

你有没有从 plyr包中查看 llply()

它完全符合你的要求。 对于列表的每个元素,应用函数,将结果保持为列表。Llply 等同于 lapplication,只不过它将保留标签 并且可以显示进度条。?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"

以 Jordan 的回答为基础,精确地说出来:

sapply(USE.NAMES=T)包装器确实会将迭代的向量值(而不是它的 name 属性,如 lapplication) 但前提是这些都是角色。设置为最终结果的名称

As a result, passing indices will not help. If you want to pass indexes with sapply, you need to resort to some (ugly) casting:

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)

在这里,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

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.

同样基于@joran 的回答,你可以写一个保留 object 属性的包装函式,比如:

lapply_preserve_names <- function(list, fun){
lapply(seq_along(list), function(i) {
obj = list[i]
names(obj) = names(list)[i]
fun(obj)
})
}

then instead of using lapply, simply use lapply_preserve_names(your_list, function)