Home > Blockchain >  Custom function to manipulate list not working in mutate when it does work in isolation
Custom function to manipulate list not working in mutate when it does work in isolation

Time:04-20

I have a data frame where one column is a list of keystrokes. I have then created a custom function to convert the list of keystrokes into the final word. As a concrete example, I start with this data:

dat <- data.frame(word=c(1,1,2,2,2,2),
                  key=c("a","b","a","b","Backspace","c"))

I then call the below to create a column with lists of keystrokes (the repeats are intentional, as I need to preserve every individual keystroke):

dat <- dat %>% 
  group_by(word) %>% 
  mutate(key_list = I(list(key))) %>% 
  ungroup()

This creates a data frame where the first 2 rows have key_list = a,b and the last 4 rows are a,b,Backspace,c. This is to be expected.

I then want to concatenate the key_list into a single string. However, I've created the custom function below because when iterating through the list, if I encounter "Backspace", I need to delete the last keystroke. Therefore, the function looks like:

library(tidyverse)

word_list_to_final_str <- function(word_list) {
  final_list = c()
  for (i in word_list) {
    if (tolower(i) %in% c(letters)) {
      final_list <- c(final_list, tolower(i))
    }
    else if (i == 'Backspace') {
      final_list <- head(final_list, -1)
    }
  }
  final_str <- str_c(final_list,collapse="")
  return(final_str)
}

When I run this function in isolation, it returns the correct result:

19:13:11> word_list_to_final_str(c("a","b","Backspace","c"))
[1] "ac"

However, when I run the function within mutate(), I get an additional column with all "abababbackspacecabbackspacecabbackspacecabbackspacec".

dat <- dat %>% 
  mutate(final_word = word_list_to_final_str(key_list))

Clearly somewhere the function is not clearing the list, but I cannot understand where. How can I change the function?

CodePudding user response:

Since you have a list column, you need to map over that list. You can use purrr to make that pretty easy

dat %>% 
  group_by(word) %>% 
  mutate(key_list = I(list(key))) %>% 
  mutate(final_word = purrr:::map_chr(key_list, word_list_to_final_str))

An every more "tidy" way to do this would be to use tidyr::nest as well

dat %>% 
  tidyr::nest(key_list = c(key)) %>% 
  mutate(final_word = purrr::map_chr(key_list, ~word_list_to_final_str(.x$key)))

CodePudding user response:

Without writing the function, you could do:

dat %>%
  group_by(word)%>%
  mutate(final_word = str_remove(str_c(key, collapse = ''), ".Backspace"))

# A tibble: 6 x 3
# Groups:   word [2]
   word key       final_word
  <dbl> <chr>     <chr>     
1     1 a         ab        
2     1 b         ab        
3     2 a         ac        
4     2 b         ac        
5     2 Backspace ac        
6     2 c         ac 
  • Related