这里我们再次去:在R中追加一个元素到列表中

我不满意接受的答案追加一个对象到R中的分摊恒定时间的列表?

> list1 <- list("foo", pi) > bar <- list("A", "B") 

我怎样才能将新的元素bar添加到list1 ? 很明显, c()不起作用,它使扁平化:

 > c(list1, bar) [[1]] [1] "foo" [[2]] [1] 3.141593 [[3]] [1] "A" [[4]] [1] "B" 

指定作品索引:

 > list1[[length(list1)+1]] <- bar > list1 [[1]] [1] "foo" [[2]] [1] 3.141593 [[3]] [[3]][[1]] [1] "A" [[3]][[2]] [1] "B" 

这种方法的效率是多less? 有没有更优雅的方式?

将元素添加到列表中时,一次只执行一个元素会非常慢。 看到这两个例子:

我将Resultvariables保留在全局环境中,以避免复制到评估框架,并通过.GlobalEnv$告诉R在哪里查找它,以避免使用<<-

 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 

慢。 现在我们来尝试第二种方法:

 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 

还是慢点。

现在让我们尝试使用一个environment ,并在这个环境中创build新的variables,而不是将元素添加到列表中。 这里的问题是variables必须被命名,所以我将使用计数器作为string来命名每个项目“插槽”:

 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 

哇快得多。 :-)这可能有点尴尬,但它的工作。

最后一种方法是使用一个列表,但是一次只增加一个元素的大小,而不是每次列表填满时的大小加倍 。 列表大小也保存在一个专用的variables,以避免使用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 

它甚至更快。 和任何列表一样容易工作。

让我们尝试使用更多迭代的最后两个解决scheme:

 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 

那么,最后一个肯定是要走的路。

这很容易。 您只需要按以下方式添加它:

 list1$bar <- bar 

在R中改变列表/向量长度的操作总是将所有元素复制到一个新列表中,所以O(n)会很慢。 在一个环境中存储是O(1),但具有较高的常量开销。 对于一个实际的O(1)追加和一些方法的基准比较看到我的答案在另一个问题在https://stackoverflow.com/a/32870310/264177