How to write a function around data.table::tstrsplit() to separate strings into different columns?

Viewed 56

This question is likely a duplicate, but I didn't find a solution so apologies in advance. I want to build a speedier alternative to tidyr::separate(), which separates a string in one column into new columns. I decided to use data.table for this task.

I created the following function:

library(data.table)
library(tibble)

fast_separate <- function(.data, origin_col, into) {
  
  my_origin_col <- deparse(substitute(origin_col))
  
  my_dt <- as.data.table(.data)
  my_dt <- my_dt[, into := tstrsplit(my_origin_col, "_", fixed = TRUE)][] # https://rdatatable.gitlab.io/data.table/reference/tstrsplit.html
  as_tibble(my_dt)
}

My function fails
Let's say I have the following toy data:

df_toms <- tribble(~toms, 
              "tom_hanks",
              "tom_bradey",
              "tom_cruise",
              "thomas_edison",
              "thomas_fefferson"
              )

df_toms
## # A tibble: 5 x 1
##   toms            
##   <chr>           
## 1 tom_hanks       
## 2 tom_bradey      
## 3 tom_cruise      
## 4 thomas_edison   
## 5 thomas_fefferson

When I call fast_separate() I get:

fast_separate(df_toms, origin_col = toms, into = c("first_name", "surname"))

## # A tibble: 5 x 2
##   toms             into 
##   <chr>            <chr>
## 1 tom_hanks        toms 
## 2 tom_bradey       toms 
## 3 tom_cruise       toms 
## 4 thomas_edison    toms 
## 5 thomas_fefferson toms 

This is not the desired output.
Which is strange because running the same code regularly (i.e., not inside a function) we get:

my_dt <- as.data.table(df_toms)
my_dt <- my_dt[, c("first_name", "surname") := tstrsplit(toms, "_", fixed = TRUE)][]
desired_output <- as_tibble(my_dt)

desired_output 
## # A tibble: 5 x 3
##   toms             first_name surname  
##   <chr>            <chr>      <chr>    
## 1 tom_hanks        tom        hanks    
## 2 tom_bradey       tom        bradey   
## 3 tom_cruise       tom        cruise   
## 4 thomas_edison    thomas     edison   
## 5 thomas_fefferson thomas     fefferson

What's wrong with the way I wrote fast_separate()?

1 Answers

This provides the needed output

library(data.table)
library(tibble)
fast_separate <- function(.data, origin_col, into) {
  as.tibble(setDT(.data)[, (into) := tstrsplit(.data[[origin_col]], "_", fixed = TRUE)])
}

df_toms <- tribble(~toms, 
                   "tom_hanks",
                   "tom_bradey",
                   "tom_cruise",
                   "thomas_edison",
                   "thomas_fefferson"
)


fast_separate(df_toms, origin_col = "toms", into = c("first_name", "surname"))
# # A tibble: 5 x 3
#   toms             first_name surname  
#   <chr>            <chr>      <chr>    
# 1 tom_hanks        tom        hanks    
# 2 tom_bradey       tom        bradey   
# 3 tom_cruise       tom        cruise   
# 4 thomas_edison    thomas     edison   
# 5 thomas_fefferson thomas     fefferson

and who is Thomas Fefferson? ;-)

Related