0

我正在开发一个 R 包,该包具有许多函数,这些函数遵循非 R 标准做法,即修改作为参数传入的对象。这通常可以正常工作,但当要修改的对象在列表中时会失败。

给出赋值形式示例的函数:

myFun<-function(x){
  xn <- deparse(substitute(x))
  ev <- parent.frame()
  # would do real stuff here ..
  # instead set simple value to modify local copy
  x[[1]]<-"b"
  # assign in parent frame
  if (exists(xn, envir = ev)) 
  on.exit(assign(xn, x, pos = ev))
  # return invisibly 
  invisible(x)
}

这有效:

> myObj <-list("a")
> myFun(myObj)
> myObj
[[1]]
[1] "b"

但如果对象是列表的成员,它就不起作用:

> myObj <-list("a")
> myList<-list(myObj,myObj)
> myFun(myList[[1]])
> myList
[[1]]
[[1]][[1]]
[1] "a"


[[2]]
[[2]][[1]]
[1] "a"

在这里阅读其他问题的答案后,我看到文档assign清楚地说明:

assign does not dispatch assignment methods, so it cannot be used to set elements of vectors, names, attributes, etc.

由于存在使用这些函数的现有代码库,我们不能放弃就地修改语法。是否有人对修改作为父框架中列表成员的对象的解决方法或替代方法有建议?

更新:

我考虑过尝试推出自己的分配功能,例如:

assignToListInEnv<-function(name,env,value){
  # assume name is something like "myList[[1]]"
  #check for brackets
  index<-regexpr('[[',name,fixed=TRUE)[1]
  if(index>0){
    lname<-substr(name,0,index-1)
    #check that it exists
    if (exists(lname,where=env)){
      target<-get(lname,pos=env)
      # make sure it is a list
      if (is.list(target)){
        eval(parse(text=paste('target',substr(name,index,999),'<-value',sep='')))
        assign(lname, target, pos = env)
      } else {
        stop('object ',lname,' is not a list in environment ',env)
      }
    } else {
      stop('unable to locate object ',lname,' in frame ',env)
    }
  }
}

但它看起来很脆弱,需要处理更多的情况($以及) [[[并且可能仍然会失败,[[x]]因为x会在错误的框架中进行评估......

4

1 回答 1

0

由于它在我的查询的第一个搜索结果中,这是我的解决方案:

您可以使用paste()"<<-" 创建一个表达式,该表达式将在评估时将值分配给您的列表元素。

assignToListInEnv<-function(name, value, env = parent.frame()){
  cl <- as.list(match.call())
  lang <- str2lang(paste(cl["name"], "<<-", cl["value"]))
  eval(lang, envir = env)
}
于 2021-12-29T05:47:50.680 回答