1

I am trying to convert an object name to a string within an anonymous function. First, I need to call the object normally within a dplyr chain, then use the object's name.

I've tried a number of methods to solve my problem but I'm unsure why they're not working. I've succeeded when calling an object directly, but not within a function in a map/lapply chain.

I've checked the three following pages: In R, how to get an object's name after it is sent to a function?

How to convert variable (object) name into String

converting a quosure to a string in R

Here's some stripped down sample work to illustrate what I'm trying to accomplish and what I've tried so far.

Data (3 tibbles):

a18 <- tibble(x = c(1,2,3), 
            y = c(1,2,3))
a19 <- tibble(x = c(1,2,3), 
            y = c(1,2,3))

dat <- 
structure(list(ID = c("12327701006", "12327601004", "12327601006", 
                      "12327601008", "12327701008", "12327701009", "12327701010", "12327701011", 
                      "12326201002", "12334201009"), GRP = c("169", "169", "169", "169", 
                                                             "169", "169", "169", "169", "170", "169"), Stat = c(8.8981219, 
                                                                                                                 4.25978943, 9.17077178, 4.13070278, 9.38120484, 4.32074928, 4.60516953, 
                                                                                                                 4.60194847, 14.23145155, 5.00784539)), class = c("tbl_df", "tbl", 
                                                                                                                                                                  "data.frame"), row.names = c(NA, -10L))

Attempt

lapply(list(a18, a19), 
       function(x) (dat %>% 
                      group_by(GRP) %>% 
                      summarize(Stat = sum(Stat)) %>% 
                      ungroup() %>% 
                      mutate(Year = paste0("20", stringr::str_sub(rlang::quo_text(quo(x)), start = -2)))) )

Output

[[1]]
# A tibble: 2 x 3
GRP    Stat Year
<chr> <dbl> <chr>
1 169    54.4 20x
2 170    14.2 20x

[[2]]
# A tibble: 2 x 3
GRP    Stat Year
<chr> <dbl> <chr>
1 169    54.4 20x
2 170    14.2 20x

Here's the output I need. It includes the full year, such as "2018" instead of "20x".

Desired Output

[[1]]
# A tibble: 2 x 3
GRP    Stat Year
<chr> <dbl> <chr>
1 169    54.4 2018
2 170    14.2 2018

[[2]]
# A tibble: 2 x 3
GRP    Stat Year
<chr> <dbl> <chr>
1 169    54.4 2019
2 170    14.2 2019

I don't understand why it's not working because when I do the following outside of the lapply call, it works, returning "18" instead of "x".

stringr::str_sub(rlang::quo_text(quo(a18)), -2)
[1] "18"
hmhensen
  • 2,974
  • 3
  • 22
  • 43

1 Answers1

1

We can use imap on a named list (which we get if we wrap with lst, remove the non-numeric part with str_remove and paste (or str_c) with the "20"

library(dplyr)
library(purrr)
library(stringr)
imap(lst(a18, a19), ~ 
     dat %>% 
         group_by(GRP) %>%
         summarize(Stat = sum(Stat)) %>%
         mutate(Year = str_c("20", str_remove(.y, "\\D+"))))

Or with str_replace

imap(lst(a18, a19), ~ 
 dat %>% 
     group_by(GRP) %>%
     summarize(Stat = sum(Stat)) %>%
     mutate(Year = str_replace(.y, "\\D+", "20")))
#$a18
# A tibble: 2 x 3
#  GRP    Stat Year 
#  <chr> <dbl> <chr>
#1 169    54.4 2018 
#2 170    14.2 2018 

#$a19
# A tibble: 2 x 3
#  GRP    Stat Year 
#  <chr> <dbl> <chr>
#1 169    54.4 2019 
#2 170    14.2 2019 

Or if we use list

list(a18 = a18, a19= a19)

Or another option is mget

mget(ls(pattern = "^a\\d+"))

Regarding why the quo() is not working, it is taking that as literal 'x'. instead of the value stored in it

stringr::str_sub(rlang::quo_text(quo(x)), -2)
#[1] "x"
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    It worked! Thanks. One question, what is the "\\D+" in the `stringr` call for? – hmhensen Jan 11 '20 at 00:35
  • 1
    @hmhensen That was just to remove all non-numeric values (i.le. one or more characters not a digit). If you have only. 'a', then simply `str_remove(.y, "a")` – akrun Jan 11 '20 at 00:36
  • 1
    @hmhensen. I would make use of `imap` or `map2` (by also passing names) instead of applying a lot of evaluations (as these are already optimized for these kind of operations) – akrun Jan 11 '20 at 00:41
  • 1
    That's the next step. I'm trying to incorporate `map2` into more of my work, but I don't run into these situations too often. – hmhensen Jan 11 '20 at 00:47