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

Viewed 110

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)
  }
2 Answers

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))

Assign the output back to listoftibbles.

for (i in seq_along(listoftibbles)) {
  listoftibbles[[i]] <- fn(listoftibbles[[i]])
  print (listoftibbles[[i]])
}
Related