我们再来一次:将一个元素附加到 R 中的列表 [英] Here we go again: append an element to a list in R

查看:18
本文介绍了我们再来一次:将一个元素附加到 R 中的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 将对象附加到 R 中的列表中以摊销常量时间?

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

如何将新元素 bar 附加到 list1?显然,c() 不起作用,它使 bar 变平:

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"

分配给索引作品:

> 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:

我将 Result 变量保留在全局环境中,以避免复制到评估框架,并使用 .GlobalEnv$ 告诉 R 在哪里寻找它,以避免使用 <<- 进行盲搜索:

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

还是很慢.

现在让我们尝试使用 environment,并在此环境中创建新变量,而不是将元素添加到列表中.这里的问题是变量必须被命名,所以我将使用计数器作为字符串来命名每个项目插槽":

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.

最后一种方法使用列表,但不是一次增加一个元素的大小,而是在每次列表满时加倍大小.列表大小也保存在一个专用变量中,以避免使用 length:

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

好吧,最后一个绝对是要走的路.

Well, the last one is definetely the way to go.

这篇关于我们再来一次:将一个元素附加到 R 中的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆