【问题标题】:how to add value to existing variable from inside a loop?如何从循环内部向现有变量添加值?
【发布时间】:2016-02-21 16:33:32
【问题描述】:

我想从循环中将计算值添加到现有向量,在该循环中从循环中调用所需向量。我正在寻找一些类似于 assign() 函数的函数,但这将使我能够将值添加到现有变量而不是创建新变量。

示例: 说我有 3 个变量:

sp=3
for(i in 1:sp){
    name<-paste("sp",i,sep="")
    assign(name,rnorm(5))
}

现在我想访问每个变量中的最后一个值,将其加倍并将结果添加到向量中:

for(i in 1:sp){
    name<-paste("sp",i,sep="")
    name[6]<-name[5]*2
}

这里的问题是“name”是一个字符串,R如何将其识别为可验证的名称并访问它?

【问题讨论】:

  • 只有非常高级的 R 程序员才应该使用assign。看起来你还没有在那里。对于使用assign 的初学者来说,总是可以替代他们的方法。例如,如果您使用列表来保存所有内容而不是在工作区中创建一堆对象,这将非常容易。
  • 谢谢罗纳德,但这只是一个例子,在这里打印我的整个巨大代码没有用,所以这是我需要的一个例子我认为分配非常好,因为我的代码是由许多变化的变量组成,这些变量并非都是预先知道的
  • 这并不意味着我的评论不适用于您的情况。我认为自己对 R 非常有经验,而且我几乎从不使用 assign
  • @etienne 这点有用....
  • assign(name,c(eval(as.symbol(name)),eval(as.symbol(name))[5]*2)) 之类的东西如果你把它放在名称分配之后的第二个循环中就可以了。但你不应该使用它。

标签: r loops variable-assignment dynamic-programming


【解决方案1】:

你要求的是这样的:

get(name)

在你的代码中它会是这样的:

v <- 1:10
var <- "v"

for (i in v){
  tmp <- get(var)
  tmp[6] <- tmp[5]*2
  assign(var, tmp)
}
# [1]  1  2  3  4  5 10  7  8  9 10

这对您有任何帮助吗?

但是,我同意另一个答案,即列表和 lapply/sapply-functions 更适合!

【讨论】:

  • 不,dosent 工作,打印错误:找不到函数“get
  • 你是对的,我应该在发布之前测试它。感谢您的通知。我更正了。
【解决方案2】:

@Roland 是绝对正确的,您绝对应该为此类问题使用列表。它更清洁,更容易使用。这是处理现有资源的另一种方式(很容易概括):

sp <- replicate(3, rnorm(5), simplify=FALSE)
names(sp) <- paste0("sp", 1:3)
sp

#$sp1
#[1] -0.3723205  1.2199743  0.1226524  0.7287469 -0.8670466
#
#$sp2
#[1] -0.5458811 -0.3276503 -1.3031100  1.3064743 -0.7533023
# 
#$sp3
#[1]  1.2683564  0.9419726 -0.5925012 -1.2034788 -0.6613149

newsp <- lapply(sp, function(x){x[6] <- x[5]*2; x})
newsp

#$sp1
#[1] -0.3723205  1.2199743  0.1226524  0.7287469 -0.8670466 -1.7340933
#
#$sp2
#[1] -0.5458811 -0.3276503 -1.3031100  1.3064743 -0.7533023 -1.5066046
#
#$sp3
#[1]  1.2683564  0.9419726 -0.5925012 -1.2034788 -0.6613149 -1.3226297

编辑:如果你真的,真诚地致力于这样做,尽管被推荐,你可以这样做:

for(i in 1:sp){
  name<-paste("sp",i,sep="")
  assign(name, `[<-`(get(name), 6, `[`(get(name), 5) * 2))
}

【讨论】:

  • 嗨,thanx,但是因为我的代码非常动态,我更喜欢使用循环技术——我的很多变量都相互连接,这就是为什么我想继续使用循环(那里是非常严格的变量名称变化)
  • @Roland 没有对变量名进行验证。我正在处理社区模型(我看到你是一名生态学家),我有许多代表许多物种特征的变量。这就是为什么我要保留 usinf "for" 循环,以便验证 os 物种变量和特征变量
  • 我正在搜索的内容是一种让 R 识别我从“粘贴”函数获得的字符串作为变量名示例的方法:将识别 paste("NO",i,sep="")作为 NO5 变量
  • @Aviv 您应该尝试理解我们想要告诉您的内容。没有任何理由在循环中创建变量并将它们放入全局环境中。将它们放入列表中。它更容易、更易读、更整洁。当然,您可能根本不需要 for 循环,但那是另一回事了……
  • @Ronald 我明白你的意思,但你为什么这么反对 for 循环?为什么列表要好得多?
【解决方案3】:

这就是您可以使用列表执行此操作的方法:

sp=3

mylist <- vector(mode = "list", length = sp) #initialize a list
names(mylist) <- paste0("sp",seq_len(sp)) #set the names

for(i in 1:sp){
  mylist[[i]] <- rnorm(5)
}

for(i in 1:sp){
  mylist[[i]] <- c(mylist[[i]], mylist[[i]][5] * 2) 
}

mylist
#$sp1
#[1]  0.6974563  0.7714190  1.1980534  0.6011610 -1.5884306 -3.1768611
#
#$sp2
#[1] -0.2276942  0.2982770  0.5504381 -0.2096708 -1.9199551 -3.8399102
#
#$sp3
#[1]  0.235280995  0.276813498  0.002567075 -0.774551774  0.766898045  1.533796089

然后您可以按照help("[") 中的说明访问列表元素,即mylist$sp1mylist[["sp1"]] 等。

当然,这仍然是非常低效的代码,可以改进很多。例如,由于所有三个变量的类型和长度都相同,因此它们确实应该组合成一个矩阵,可以通过一次调用 rnorm 来填充该矩阵,并且还允许使用矢量化操作进行第二次操作。

【讨论】:

    猜你喜欢
    • 2019-03-30
    • 2015-05-05
    • 1970-01-01
    • 2021-02-18
    • 2017-03-05
    • 2020-10-17
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多