在这里,我们又来了:一个元素追加到R A名单 [英] Here we go again: append an element to a list in R
问题描述
我不开心的接受的答案,<一个href=\"http://stackoverflow.com/questions/2436688/append-an-object-to-a-list-in-r-in-amortized-constant-time\">Append一个对象在固定的时间里R中的列表?
I am not happy with the accepted answer to Append an object to a list in R in amortized constant time?
> list1 <- list("foo", pi)
> bar <- list("A", "B")
我如何可以将新的元素栏
到 list1的
?显然, C()
不起作用,它变平栏
:
How can I append new element bar
to list1
? Clearly, c()
does not work, it flattens 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?
推荐答案
在一个时间做一个元素时将元素添加到列表是很慢的。看到这两个例子:
Adding elements to a list is very slow when doing it one element at a time. See these two examples:
我保持结果
变量在全球环境中,以避免副本评估框架,并告诉R其中寻找它与 .GlobalEnv $
,以避免盲目搜索&LT;&LT; -
:
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 <- 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
仍然缓慢。
现在,让我们尝试使用环境
,并创造这种环境,而不是将元素添加到列表中的新变量。这里的问题是,必须对变量进行命名的,所以我会用计数器作为一个字符串,命名每个项目老虎:
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":
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 doubles the size each time the list is full. The list size is also kept in a dedicated variable, to avoid any slowdown using 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
好了,最后一个是definetely的路要走。
Well, the last one is definetely the way to go.
这篇关于在这里,我们又来了:一个元素追加到R A名单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!