combine multiple columns in R into a new vector column (preferably a tidyr solution)

Viewed 867

I am trying to combine multiple columns into a vector (ideally I would like to specify which columns using some regex or dplyr::contains(). Anyways, I am NOT looking to concatenate columns or a solution using paste (I want to be able to use an %in% statement on the resulting vector. I want the new column to be a vector of values, which could be unnested using unnest_wider or some similar function. I am sure this is possible, just can't think of the right search terms for now. This seems to be close, but does not work:

df <- tribble(~A, ~B,
               1, 2, 
               3, 4, 
               5, 6)

df %>%
    mutate(C = I(list(A, B)))

The result would look something like this

      A     B    C
1     1     2   c(1,2)
2     3     4   c(3,4)
3     5     6   c(5,6)
1 Answers

Here, we can either use rowwise

library(dplyr)
df %>%
   rowwise %>%
   mutate(C = list(c(A, B))) %>%
   ungroup
# A tibble: 3 x 3
#      A     B C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>

Or with map2 which by default return a list. Here, we are looping over corresponding elements of 'A', 'B', and concatenating (c)

library(dplyr)
library(purrr)
df %>%
   mutate(C = map2(A, B, c))
# A tibble: 3 x 3
#      A     B C        
#   <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>

Update

Based on OP's comments, if we want to create a list column with only columns that have a suffix _id

names(df) <- paste0(names(df), "_id")
df %>%
    rowwise %>%
    mutate(C = list(c_across(ends_with("_id")))) %>%
    ungroup

-output

# A tibble: 3 x 3
#   A_id  B_id C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>

If the substring "_id" is at the beginning, change the ends_with to starts_with or use matches("^_id")

Or with pmap

df %>%
     mutate(C = pmap(select(., ends_with("_id")), ~ c(...)))

-output

# A tibble: 3 x 3
#   A_id  B_id C        
#  <dbl> <dbl> <list>   
#1     1     2 <dbl [2]>
#2     3     4 <dbl [2]>
#3     5     6 <dbl [2]>

Or using Map from base R

df$C <-  do.call(Map, c(f = c, df[grep("_id", names(df))]))
Related