R for循环内使用eval(parse)向全局环境赋值向量仅保留最后一位问题
问题根源
你的代码问题出在paste()拼接赋值表达式的逻辑上:当eg1()返回长度大于1的向量时,paste(x[i+2],"<<-",result)会把向量的每个元素单独和赋值语句拼接,生成多段赋值语句,eval(parse())会按顺序执行所有语句,最终只有最后一个元素的赋值生效,所以你得到的永远是向量最后一位的值。
举个实际的例子:当你对"eg0*2"求值得到c(2,4,6)时,原代码的paste操作会生成如下长度为3的字符向量:
["eg0_multiplied_by_2 <<- 2", "eg0_multiplied_by_2 <<- 4", "eg0_multiplied_by_2 <<- 6"]
执行后变量自然只会保留最后一个值6。
解决方案
方案1:使用assign()函数(推荐,无字符串拼接风险)
直接用R内置的assign()函数向指定环境写入对象,不需要手动构造赋值表达式,天然支持任意长度、任意类型的R对象:
eg3 <- function(vector){ x <- vector x2 <- c() for(i in 1:(length(x)-1)){ # 注意输入vector是字符向量,所以判断条件要和字符串"1"比较 if(x[i+1] == "1") x2[length(x2)+1] <- x[i] if(x[i+1] == "2"){ result <- eg1(x[i]) # 直接向全局环境赋值变量 assign(x = x[i+2], value = result, envir = globalenv()) } } }
方案2:兼容原有eval(parse())写法的修改
如果一定要保留原有的表达式拼接逻辑,需要用deparse()函数将返回的R对象转为合法的R表达式字符串再拼接:
eg3 <- function(vector){ x <- vector x2 <- c() for(i in 1:(length(x)-1)){ if(x[i+1] == "1") x2[length(x2)+1] <- x[i] if(x[i+1] == "2"){ result <- eg1(x[i]) # deparse会把R对象转成符合语法的字符串 eval(parse(text = paste( x[i+2], "<<-", deparse(result) )), envir = globalenv()) } } }
验证效果
修改后运行你提供的测试代码,全局环境生成的two_plus_two会返回4,eg0_multiplied_by_2会返回长度为3的向量2 4 6,和直接调用eg1("eg0*2")的结果完全一致。
内容的提问来源于stack exchange,提问作者GEX_HEX_420
相关产品推荐
相关产品推荐

