A list-based version of unite() and separate(). Creates a list column that contains named lists, instead of a character vector.

Use case:

Implementation (zip)

zip <- function(data, col, ..., remove = TRUE) {
  col <- tidyr:::col_name(substitute(col))
  from <- dplyr::select_vars(names(data), ...)

  zip_(data, col, from, remove = remove)
}

zip_ <- function(data, col, from, remove = TRUE) {
  UseMethod("zip_")
}

zip_.data.frame <- function(data, col, from, remove = TRUE) {
  united <- lapply(purrr::zip_n(data[from]), setNames, nm = from)

  first_col <- which(names(data) %in% from)[1]
  data2 <- tidyr:::append_col(data, united, col, after = first_col - 1)

  if (remove) {
    data2 <- data2[setdiff(names(data2), from)]
  }

  data2
}

Example:

library(tidyr)
library(dplyr)
## 
## Attaching package: 'dplyr'
## 
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## 
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
data <- expand.grid(c=letters[1:2], d=letters[3:4], key=1:2) %>%
  tbl_df %>%
  mutate(value1 = 1:8, value2 = LETTERS[1:8])
data
## Source: local data frame [8 x 5]
## 
##        c      d   key value1 value2
##   (fctr) (fctr) (int)  (int)  (chr)
## 1      a      c     1      1      A
## 2      b      c     1      2      B
## 3      a      d     1      3      C
## 4      b      d     1      4      D
## 5      a      c     2      5      E
## 6      b      c     2      6      F
## 7      a      d     2      7      G
## 8      b      d     2      8      H
zipped <- data %>% zip("values", value1, value2)
zipped
## Source: local data frame [8 x 4]
## 
##        c      d   key    values
##   (fctr) (fctr) (int)     (chr)
## 1      a      c     1 <list[2]>
## 2      b      c     1 <list[2]>
## 3      a      d     1 <list[2]>
## 4      b      d     1 <list[2]>
## 5      a      c     2 <list[2]>
## 6      b      c     2 <list[2]>
## 7      a      d     2 <list[2]>
## 8      b      d     2 <list[2]>
zipped$values[[1]]
## $value1
## [1] 1
## 
## $value2
## [1] "A"
spread_res <- zipped %>% spread(key, values)
spread_res
## Source: local data frame [4 x 4]
## 
##        c      d         1         2
##   (fctr) (fctr)     (chr)     (chr)
## 1      a      c <list[2]> <list[2]>
## 2      a      d <list[2]> <list[2]>
## 3      b      c <list[2]> <list[2]>
## 4      b      d <list[2]> <list[2]>
spread_res[1,]$`1`
## [[1]]
## [[1]]$value1
## [1] 1
## 
## [[1]]$value2
## [1] "A"
spread_res[1,]$`2`
## [[1]]
## [[1]]$value1
## [1] 5
## 
## [[1]]$value2
## [1] "E"