I am trying to extract the last element from the list nuts
. In one row, however, the content is character(0)
. Hence, the extraction of the last element fails. I am struggling to control for the presence of character(0)
. Any help? Many thanks.
library(tidyverse)
my_df <- tibble(
txt=c("chestnut, pear, kiwi, peanut",
"grapes, banana"))
#Extract all nuts
my_df <- my_df %>%
mutate(nuts=str_extract_all(txt, regex("\\w*nut\\w*")))
#there were no nuts in the second row; hence character(0)
my_df$nuts
#> [[1]]
#> [1] "chestnut" "peanut"
#>
#> [[2]]
#> character(0)
#now i want to extract the last element from the list; doesn't work
my_df %>%
mutate(last_item=map_chr(nuts, ~tail(.x, 1)))
#> Error in `mutate_cols()`:
#> ! Problem with `mutate()` column `last_item`.
#> i `last_item = map_chr(nuts, ~tail(.x, 1))`.
#> x Result 2 must be a single string, not a character vector of length 0
#> Caused by error in `stop_bad_type()`:
#> ! Result 2 must be a single string, not a character vector of length 0
#the reason for the failure is the second row with character(0), the other row works,
my_df %>%
slice(., 1) %>%
mutate(last_item=map_chr(nuts, ~tail(.x, 1)))
#> # A tibble: 1 x 3
#> txt nuts last_item
#> <chr> <list> <chr>
#> 1 chestnut, pear, kiwi, peanut <chr [2]> peanut
#how to make analysis account for the presence of character(0);
#Attempt 1: purrr::possibly doesn't work either
my_df %>%
slice(., 1) %>%
mutate(last_item=map_chr(nuts, ~purrr::possibly(tail(.x, 1),
otherwise="NA")))
#> Error in `mutate_cols()`:
#> ! Problem with `mutate()` column `last_item`.
#> i `last_item = map_chr(nuts, ~purrr::possibly(tail(.x, 1), otherwise = "NA"))`.
#> x Can't coerce element 1 from a closure to a character
#> Caused by error:
#> ! Can't coerce element 1 from a closure to a character
#Attempt 2: Circumvent the issue by taking the length of the list into consideration;
#but my map - command doesn't work now.
my_df %>%
mutate(list_length=map_dbl(nuts, length)) %>%
mutate(last_item=case_when(
list_length>0 ~ ~map_chr(nuts, ~tail(.x, 1)),
list_length==0 ~ NA_character_))
#> Error in `mutate_cols()`:
#> ! Problem with `mutate()` column `last_item`.
#> i `last_item = case_when(...)`.
#> x must have class `call`, not class `formula`.
#> Caused by error in `glubort()`:
#> ! must have class `call`, not class `formula`.
Created on 2022-03-15 by the reprex package (v2.0.1)
CodePudding user response:
You can do:
my_df |>
rowwise() |>
mutate(last_item = ifelse(length(nuts) == 0L, unlist(nuts), nuts[[length(nuts)]])) |>
ungroup()
# A tibble: 2 x 3
txt nuts last_item
<chr> <list> <chr>
1 chestnut, pear, kiwi, peanut <chr [2]> peanut
2 grapes, banana <chr [0]> NA
CodePudding user response:
library(tidyverse)
my_df <- tibble(
txt = c(
"chestnut, pear, kiwi, peanut",
"grapes, banana"
)
) %>%
mutate(nuts = str_extract_all(txt, regex("\\w*nut\\w*")))
my_df %>%
mutate(
last_item = nuts %>% map_chr(last)
)
#> # A tibble: 2 × 3
#> txt nuts last_item
#> <chr> <list> <chr>
#> 1 chestnut, pear, kiwi, peanut <chr [2]> peanut
#> 2 grapes, banana <chr [0]> <NA>
my_df %>%
mutate(
# can not use map_chr becasue NA is not of class character
last_item = nuts %>% map(possibly(~tail(.x, 1), NA))
)
#> # A tibble: 2 × 3
#> txt nuts last_item
#> <chr> <list> <list>
#> 1 chestnut, pear, kiwi, peanut <chr [2]> <chr [1]>
#> 2 grapes, banana <chr [0]> <chr [0]>
Created on 2022-03-15 by the reprex package (v2.0.0)