Search code examples
rlistfunctionglobaltibble

R - Why does my function appear to work but not update tibbles within a list?


I have a list of tibbles and use the code below I expect that each tibble in the list will have a column added with a factor (one of 16 levels). I can see exactly what I want being printed to the console, but in the global environment, my list of tibbles remains the same. What am I doing wrong?


fn <- function(df){
  df$col1 = cut(df$col1, 16)
  return(df)
  
for (df in listoftibbles){
    df <- fn(df)
    print (df)
  }

Solution

  • In the for loop, it is not updating the element in listoftibbles i.e.. if we want to do this, loop over the sequence of the object and update by assignment

    for(ind in seq_along(listoftibbles)) {
        listoftibbles[[ind]] <- fn(listoftibbles[[ind]])
    }
    

    The for loop in R is a for each loop which returns the values of the list element. The 'df' object is a temporary object created on the fly. This can be checked via ls (suppose there are 2 list elements)

    > ls(pattern = '^df$')
    character(0) # no object 
    > for(df in listoftibbles) print(ls(pattern = '^df$'))
    [1] "df"
    [1] "df"
    
    > ls(pattern = '^df$')
    [1] "df" # now there is an object
    

    The value of the object 'df' will be the last tibble of listoftibbles

    and the address can be checked as well

    > for(df in listoftibbles) print(tracemem(df))
    [1] "<0x7fe59eb4f6c0>"
    [1] "<0x7fe598361ac8>"
    > tracemem(df) # last object created 
    [1] "<0x7fe598361ac8>"
    

    We can use lapply (First posted here)

    listoftibbles <- lapply(listoftibbles, fn)
    

    Or this doesn't need any function

    listoftibbles <- lapply(listoftibbles, transform, col1 = cut(col1, 16))
    

    or with map

    library(dplyr)
    library(purrr)
    listoftibbles <- map(listoftibbles, mutate, col1 = cut(col1, 16))