list 我们再来一次:将一个元素附加到 R 中的列表中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17046336/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Here we go again: append an element to a list in R
提问by user443854
I am not happy with the accepted answer to Append an object to a list in R in amortized constant time?
我对在摊销固定时间内将对象附加到 R 中的列表的公认答案不满意?
> list1 <- list("foo", pi)
> bar <- list("A", "B")
How can I append new element bar
to list1
? Clearly, c()
does not work, it flattens bar
:
如何将新元素附加bar
到list1
?显然,c()
不起作用,它变平了bar
:
> c(list1, bar)
[[1]]
[1] "foo"
[[2]]
[1] 3.141593
[[3]]
[1] "A"
[[4]]
[1] "B"
Assignment to index works:
分配给索引工作:
> list1[[length(list1)+1]] <- bar
> list1
[[1]]
[1] "foo"
[[2]]
[1] 3.141593
[[3]]
[[3]][[1]]
[1] "A"
[[3]][[2]]
[1] "B"
What is the efficiency of this method? Is there a more elegant way?
这种方法的效率如何?有没有更优雅的方式?
回答by Ferdinand.kraft
Adding elements to a list is very slow when doing it one element at a time. See these two examples:
一次添加一个元素到列表中的速度非常慢。看这两个例子:
I'm keeping the Result
variable in the global environment to avoid copies to evaluation frames and telling R where to look for it with .GlobalEnv$
, to avoid a blind search with <<-
:
我将Result
变量保留在全局环境中以避免复制到评估框架并告诉 R 在哪里寻找它.GlobalEnv$
,以避免盲目搜索<<-
:
Result <- list()
AddItemNaive <- function(item)
{
.GlobalEnv$Result[[length(.GlobalEnv$Result)+1]] <- item
}
system.time(for(i in seq_len(2e4)) AddItemNaive(i))
# user system elapsed
# 15.60 0.00 15.61
Slow. Now let's try the second approach:
减缓。现在让我们尝试第二种方法:
Result <- list()
AddItemNaive2 <- function(item)
{
.GlobalEnv$Result <- c(.GlobalEnv$Result, item)
}
system.time(for(i in seq_len(2e4)) AddItemNaive2(i))
# user system elapsed
# 13.85 0.00 13.89
Still slow.
还是慢。
Now let's try using an environment
, and creating new variables within this environment instead of adding elements to a list. The issue here is that variables must be named, so I'll use the counter as a string to name each item "slot":
现在让我们尝试使用environment
, 并在此环境中创建新变量,而不是将元素添加到列表中。这里的问题是变量必须被命名,所以我将使用计数器作为字符串来命名每个项目“插槽”:
Counter <- 0
Result <- new.env()
AddItemEnvir <- function(item)
{
.GlobalEnv$Counter <- .GlobalEnv$Counter + 1
.GlobalEnv$Result[[as.character(.GlobalEnv$Counter)]] <- item
}
system.time(for(i in seq_len(2e4)) AddItemEnvir(i))
# user system elapsed
# 0.36 0.00 0.38
Whoa much faster. :-) It may be a little awkward to work with, but it works.
哇快多了。:-) 使用起来可能有点尴尬,但它确实有效。
A final approach uses a list, but instead of augmenting its size one element at a time, it doublesthe size each time the list is full. The list size is also kept in a dedicated variable, to avoid any slowdown using length
:
最后一种方法使用列表,但不是一次增加一个元素的大小,而是在每次列表满时将大小加倍。列表大小也保存在一个专用变量中,以避免使用length
:
Counter <- 0
Result <- list(NULL)
Size <- 1
AddItemDoubling <- function(item)
{
if( .GlobalEnv$Counter == .GlobalEnv$Size )
{
length(.GlobalEnv$Result) <- .GlobalEnv$Size <- .GlobalEnv$Size * 2
}
.GlobalEnv$Counter <- .GlobalEnv$Counter + 1
.GlobalEnv$Result[[.GlobalEnv$Counter]] <- item
}
system.time(for(i in seq_len(2e4)) AddItemDoubling(i))
# user system elapsed
# 0.22 0.00 0.22
It's even faster. And as easy to a work as any list.
它甚至更快。和任何列表一样容易工作。
Let's try these last two solutions with more iterations:
让我们尝试更多迭代的最后两个解决方案:
Counter <- 0
Result <- new.env()
system.time(for(i in seq_len(1e5)) AddItemEnvir(i))
# user system elapsed
# 27.72 0.06 27.83
Counter <- 0
Result <- list(NULL)
Size <- 1
system.time(for(i in seq_len(1e5)) AddItemDoubling(i))
# user system elapsed
# 9.26 0.00 9.32
Well, the last one is definetely the way to go.
好吧,最后一个绝对是要走的路。
回答by PAC
It's very easy. You just need to add it in the following way :
这很容易。您只需要按以下方式添加它:
list1$bar <- bar
回答by JanKanis
Operations that change the length of a list/vector in R always copy all the elements into a new list, and so will be slow, O(n). Storing in an environment is O(1) but has a higher constant overhead. For an actual O(1) append and benchmark comparison of a number of approaches see my answer to the other question at https://stackoverflow.com/a/32870310/264177.
在 R 中更改列表/向量长度的操作总是将所有元素复制到新列表中,因此速度会很慢,O(n)。在环境中存储是 O(1) 但具有更高的恒定开销。有关多种方法的实际 O(1) 附加和基准比较,请参阅我对https://stackoverflow.com/a/32870310/264177上的另一个问题的回答。