for loop list : numeric to character

I have a list of data frames. For every data frame, I am trying convert every variable as character. How could I use for loop to accomplish the task?

Here is my failed attempt:

# Example df and list
df1 <- data.frame(var1 = 1:10, var2 = as.character(50:59))
df2 <- data.frame(var1 = as.character(1:10), var2 = 50:59)
file_list <- list(df1, df2)

# Failed attempt
df_list <- vector("list", length(file_list))
for (df in file_list){
  df_list[df] <- file_list[[df]] %>% 
    mutate(across(where(is.numeric), as.character))
}

Rather than a for loop, I would use the map() function from the purrr package.

df1 <- data.frame(var1 = 1:10, var2 = as.character(50:59))
df2 <- data.frame(var1 = as.character(1:10), var2 = 50:59)
file_list <- list(df1, df2)
str(file_list)
#> List of 2
#>  $ :'data.frame':    10 obs. of  2 variables:
#>   ..$ var1: int [1:10] 1 2 3 4 5 6 7 8 9 10
#>   ..$ var2: chr [1:10] "50" "51" "52" "53" ...
#>  $ :'data.frame':    10 obs. of  2 variables:
#>   ..$ var1: chr [1:10] "1" "2" "3" "4" ...
#>   ..$ var2: int [1:10] 50 51 52 53 54 55 56 57 58 59
library(dplyr, warn.conflicts = FALSE)
library(purrr)
MyFunc <- function(V) !is.character(V)
dfList <- map(file_list, ~mutate_if(.x, MyFunc, as.character))
str(dfList)
#> List of 2
#>  $ :'data.frame':    10 obs. of  2 variables:
#>   ..$ var1: chr [1:10] "1" "2" "3" "4" ...
#>   ..$ var2: chr [1:10] "50" "51" "52" "53" ...
#>  $ :'data.frame':    10 obs. of  2 variables:
#>   ..$ var1: chr [1:10] "1" "2" "3" "4" ...
#>   ..$ var2: chr [1:10] "50" "51" "52" "53" ...

Created on 2020-08-27 by the reprex package (v0.3.0)

1 Like

Thanks a lot! It works perfectly.

Would you please explain the mechanism behind this function: MyFunc <- function(V) !is.character(V) ? I am just trying to learn. Thanks again!

The mutate_if function operates on columns where its .predicate argument, MyFunc in this case, is TRUE. We want to apply as.character to every column that is not already character but there is no function that directly returns the inverse of is.character. I made MyFunc to do that: !is.character() is TRUE whenever the vector passed to it is not a character vector. I could have written

dfList <- map(file_list, ~mutate_if(.x, is.numeric, as.character))

and that would have worked just as well if your data are limited to being either character or numeric. However, if a column is filled with TRUE/FALSE values, both is.numeric and is.character will be FALSE.

1 Like

Many thanks for the detailed explanation! It makes sense now. Thanks again!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.