Extract String Part to Column in R

Viewed 234

Consider the following dataframe:

     status
1    file-status-done-bad
2    file-status-maybe-good
3    file-status-underreview-good 
4    file-status-complete-final-bad  

We want to extract the last part of status, wherein part is delimited by -. Such:

     status                          status_extract
1    file-status-done-bad            done
2    file-status-maybe-good          maybe
3    file-status-ok-underreview-good underreview
4    file-status-complete-final-bad  final

In SQL this is easy, select split_part(status, '-', -2).

However, the solutions I've seen with R either operate on vectors or are messy to extract particular elements (they return ALL elements). How is this done in a mutate chain? The below is a failed attempt.

df %>%
mutate(status_extract = str_split_fixed(status, pattern = '-')[[-2]])
4 Answers

Found the a really simple answer.

library(tidyverse)

df %>%
  mutate(status_extract = word(status, -1, sep = "-"))

You can use map() and nth() to extract the nth value from a vector.

library(tidyverse)

df %>%
  mutate(status_extract = map_chr(str_split(status, "-"), nth, -2))

#                           status status_extract
# 1           file-status-done-bad           done
# 2         file-status-maybe-good          maybe
# 3   file-status-underreview-good    underreview
# 4 file-status-complete-final-bad          final

which is equivalent to a base version like

sapply(strsplit(df$status, "-"), function(x) rev(x)[2])

# [1] "done"        "maybe"       "underreview" "final"

In base R you can combine the functions sapply and strsplit

df$status_extract <- sapply(strsplit(df$status, "-"), function(x) x[length(x) - 1])

#                           status status_extract
# 1           file-status-done-bad           done
# 2         file-status-maybe-good          maybe
# 3   file-status-underreview-good    underreview
# 4 file-status-complete-final-bad          final

You can use regex to get what you want without splitting the string.

sub('.*-(\\w+)-.*$', '\\1', df$status)
#[1] "done"        "maybe"       "underreview" "final"    
Related