tidyr::expand() for a single column across groups

  • A+
Category:Languages

tidyr::expand() returns all possible combinations of values from multiple columns. I'm looking for a slightly different behavior, where all the values are in a single column and the combinations are to be taken across groups.

For example, let the data be defined as follows:

library( tidyverse ) X <- bind_rows( data_frame(Group = "Group1", Value = LETTERS[1:3]),                 data_frame(Group = "Group2", Value = letters[4:5]) ) 

We want all combinations of values from Group1 with values from Group2. My current clunky solution is to separate the values across multiple columns

Y <- X %>% group_by(Group) %>% do(vals = .$Value) %>% spread(Group, vals) # # A tibble: 1 x 2 #   Group1    Group2    #   <list>    <list>    # 1 <chr [3]> <chr [2]> 

followed by a double unnest operation

Y %>% unnest( .preserve = Group2 ) %>% unnest # # A tibble: 6 x 2 #   Group1 Group2 #   <chr>  <chr>  # 1 A      d      # 2 A      e      # 3 B      d      # 4 B      e      # 5 C      d      # 6 C      e      

This is the desired output, but as you can imagine, this solution doesn't generalize well: as the number of groups increases, so does the number of unnest operations that we have to perform.

Is there a more elegant solution?

 


Because OP seems happy to use base, I upgrade my comment to an answer:

expand.grid(split(X$Value, X$Group)) #   Group1 Group2 # 1      A      d # 2      B      d # 3      C      d # 4      A      e # 5      B      e # 6      C      e 

As noted by OP, expand.grid converts character vectors to factors. To prevent that, use stringsAsFactors = FALSE.

The tidyverse equivalent is purrr::cross_df, which doesn't coerce to factor:

cross_df(split(X$Value, X$Group)) # A tibble: 6 x 2 # Group1 Group2 # <chr>  <chr>  # 1 A      d      # 2 B      d      # 3 C      d      # 4 A      e      # 5 B      e      # 6 C      e 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: