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.

これらの関数を使用する既存のコードベースがあるため、modify-in-place 構文を放棄することはできません。親フレームのリストのメンバーであるオブジェクトを変更するための回避策または代替アプローチについて提案がある人はいますか?

アップデート:

次のような独自の代入関数をロールしようと考えました。

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