Using purrr to rename list objects in a list of tibbles, based on the content of those tibbles

I have a tibble that I've been asked to break down into certain combinations and send as sheets in an Excel document. So I'm using dplyr::group_split() to break the tibble into said combinations, and from there I can use writexl::write_xlsx() to write each tibble in the list to a sheet in an Excel document. For an interaction of two variables within the mtcars dataset, it would look like so:

mtcars %>% 
  dplyr::group_split(gear, carb) %>% 
  writexl::write_xlsx(path = here::here("temp.xlsx"))

Which, for mtcars, leaves me with an Excel file with 11 sheets (more in reality). However, as the list objects are unnamed the sheets are also unnamed.

Thus, what I want to do, programmatically, is set the names of the list objects based on what the content of the two columns in question are in each tibble. I figured I'd use purrr::set_names() for this.

So that you have an idea of the naming of the list objects, it would be something like this:

library(tidyverse)
library(glue)

mtcars %>% 
  group_split(gear, carb) %>% 
  map(.x = .,
      .f = ~glue("gear_{first(.$gear)}_carb_{first(.$carb)}"))

## Actual output ## 
#[[1]]
#gear_3_carb_1
#
#[[2]]
#gear_3_carb_2
#
#[[3]]
#gear_3_carb_3
#
#[[4]]
#gear_3_carb_4
#
#[[5]]
#gear_4_carb_1
#
#[[6]]
#gear_4_carb_2
#
#[[7]]
#gear_4_carb_4
#
#[[8]]
#gear_5_carb_2
#
#[[9]]
#gear_5_carb_4
#
#[[10]]
#gear_5_carb_6
#
#[[11]]
#gear_5_carb_8

So now that I have the way of creating the names. Here's my actual attempt at doing so with map2

mtcars %>% 
  group_split(gear, carb) %>% 
  map2(.x = .,
       .y = glue("gear_{first(.$gear)}_carb_{first(.$carb)}"),
       .f = ~set_names(x = .x,
                       nm = .y))

But all it returns is an empty list

#list()

Here's what I was hoping/expecting to happen:

mtcars %>% 
  group_split(gear, carb) %>% 
  map2(.x = .,
       .y = glue("gear_{first(.$gear)}_carb_{first(.$carb)}"),
       .f = ~set_names(x = .x,
                       nm = .y)) %>% 
  head(1) 

## Not actually what gets outputted ##
#$`gear_3_carb_1`
## A tibble: 3 x 11
#    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
#  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
#1  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
#2  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
#3  21.5     4  120.    97  3.7   2.46  20.0     1     0     3     1

Alas, that's not what happens, and I'm rather confused :smiley:

So my question is: What am I missing? And if my thinking about this is wholly wrong, what other programmatic, "within-pipe" way is there to achieve something like this?

Since the names should be set for the entire list, I couldn't think of a way to do this within a map() call (where you are working with an element within the list). The only thing I could come up with so far was to do your naming map() within set_names().

mtcars %>% 
    group_split(gear, carb) %>% 
    set_names(., nm = map(.x = ., ~glue("gear_{first(.x$gear)}_carb_{first(.x$carb)}") ) )

$gear_3_carb_1
# A tibble: 3 x 11
    mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
  <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1
2  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1
3  21.5     4  120.    97  3.7   2.46  20.0     1     0     3     1

$gear_3_carb_2
# A tibble: 4 x 11
...

I haven't figured out naming yet with these new group_*() functions, although they're pretty new and I could see them changing over time. I have a tendency to use group names like you are here, which means I'm still defaulting to split() a lot for the convenience of named lists.

4 Likes

Ahh, of course! That's perfect. Thanks so much! :smiley:

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.