0

I have a list mylist which gets populated in a recursive function -- however, when accessing the elements later within the recursion, they are still NULL.

A minimal example:

mylist = vector("list",5)

myf = function(x){
    if(x==1){
        mylist[[x]] = "hi"
        message("Set value at position ",x," to ",mylist[[x]])
        force(mylist[[x]] = "hi")
    }
    else{
        mylist[[x]] = "hi"
        message("Set value at position ",x," to ",mylist[[x]])
        myf(x-1)
        message("Value at position ",x-1, " is ",mylist[[x-1]])
    }
}

Which yields

Set value at position 4 to hi
Set value at position 3 to hi
Set value at position 2 to hi
Set value at position 1 to hi
Value at position 1 is 
Value at position 2 is 
Value at position 3 is 

You can see that I tried force(...) but without success.

On the discussion of global vs local variable, it has been suggested here to use <<- instead of the = assignment symbol to set the global variable. However, this does not help here. It has been further recommended in answers to that post to use assign(...) but it looks to me as if that would not work for lists.

black
  • 1,151
  • 3
  • 18
  • 46
  • `force` is not intended to be used in that way. It is only a trivial function thats return his argument, only to make it clear that it is evaluated (writing force(x) is the same that writing x alone in a line). In fact, your code is not valid code. – Ric Nov 03 '22 at 00:58
  • My first attempt was to use`force(mylist[[x]])`, but that does not work either unfortunately. – black Nov 03 '22 at 01:06

1 Answers1

0

assign will allow you to accomplish your goal. The <<- operator would work too.

mylist <- vector("list", 5)

myf <- function(x){ 
  if (x == 1) {
    mylist[[ x ]] = "hi" # <-- local assignment
    message("Set value at position ", x, " to ", mylist[[ x ]]) # local
    mylist[[ x ]] = "hi" # <-- local assignment
    assign('mylist', mylist, envir = parent.frame())  # <-- assign to mylist in parent environment
    tmp <- get('mylist', envir = parent.frame())
    message('mylist in parent envirnonment: ')
    print(tmp)
  }
  else {
    mylist[[ x ]] = "hi" # <-- local assignment
    message("Set value at position ", x, " to ", mylist[[ x ]]) # local
    myf(x-1) # <-- recursive call
    message("Value at position ", x-1, " is ", mylist[[ x-1 ]]) # local
    assign('mylist', mylist, envir = parent.frame())  # <-- assign to mylist in parent environment
    tmp <- get('mylist', envir = parent.frame())
    message('mylist in parent envirnonment: ')
    print(tmp)
  }
}

myf(1)
mylist
myf(2)
mylist
myf(3)
mylist

See also: http://adv-r.had.co.nz/Environments.html

br00t
  • 1,440
  • 8
  • 10
  • Thank you -- does the assignment copy the *entire* list every time? I.e. instead of writing one value (the new one), `length(mylist)` many write operations happen? – black Nov 03 '22 at 15:43
  • `assign('mylist', mylist, envir = parent.frame())` overwrites the entire copy of `mylist` in the parent environment with the one from the local environment. If you want to maintain the state of the copy in the parent environment, you should use `mylist <- get('mylist', envir = parent.frame())` to bring the modified `mylist` from parent envir into local, modify that copy and then assign it back to the parent environment. – br00t Nov 03 '22 at 15:52