Search code examples
rfunctionrbind

Why is rbind not working inside a user defined function?


I am trying to append rows to a dataframe inside a user defined function. I have done this before in a for loop without difficulty, as follows:

t1 <- data.frame(a=character(),
                 b=numeric())
for(i in 1:2){
    tmp.df <- data.frame(a="apple", b=i)
    t1 <- rbind(t1,tmp.df)
}

I get a dataframe with two observations.

But when I try and do a similar thing inside a function, it doesn't work. I have tried debugging the function and at the rbind step it just seems to exit the function without carrying out that step. So the following code ends up with the original empty data frame.

t1 <- data.frame(a=character(),
                 b=numeric())

create.rows <- function(id, it){
  if(it==1){
    
    tmp.df <- data.frame(a=id, b=it)
    t1 <- rbind(t1,tmp.df)
  }else{
    tmp.df <- data.frame(a=id, b=99)
    t1 <- rbind(t1,tmp.df)
  }
}

Why is this happening and what can I do to fix it?

Note that I do not know in advance how many rows there will be in the dataframe so I can't write directly to a particular row.


Solution

  • Within a function one needs to specify the <<- form of the assignment operator to get R to search through parent environments to find the object on the left side of the assignment operator and assign it a new value.

    t1 <- data.frame(a=character(),
                     b=numeric())
    
    create.rows <- function(id, it){
         if(it==1){
              
              tmp.df <- data.frame(a=id, b=it)
              t1 <<- rbind(t1,tmp.df)
         }else{
              tmp.df <- data.frame(a=id, b=99)
              t1 <<- rbind(t1,tmp.df)
         }
    }
    
    create.rows(1,1)
    create.rows(1,2)
    t1
    

    ...and the output:

    > t1
      a  b
    1 1  1
    2 1 99
    

    For additional details on behavior of the three forms of the assignment operator (=, <- and <<-), review the help page for assignment operator, where the relevant section says:

    The operators <<- and ->> are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment.