The rudimentary ( microbenchmark::microbenchmark ) benchmarking shows quite significant acceleration using:
library(tidyr) library(magrittr) df <- data.frame(x, y, z) df %>% complete(x, y, z) %>% unite("combo", x, y, z, sep = "_")
A bit slower, but perhaps a more straightforward and vectorized apply option:
df <- expand.grid(x, y, z) df$combo <- paste(df$Var1, df$Var1, df$Var3, sep = "_")
Someone should listen using the data.table approach ...
Benchmarking: small grid (256 elements)
set.seed(21034) x <- sample(letters, 4, TRUE) y <- sample(letters, 4, TRUE) z <- sample(letters, 4, TRUE) a <- sample(letters, 4, TRUE) library(data.table) library(microbenchmark) library(magrittr) library(tidyr) microbenchmark(times = 25L, DT1 = CJ(x, y, z, a)[ , paste(V1, V2, V3, V4, sep = "_")], DT2 = CJ(x, y, z, a)[ , do.call(paste, c(.SD, sep = "_"))], app1 = do.call(paste, c(expand.grid(x, y, z, a), sep = "_")), app2 = paste((df <- expand.grid(x, y, z, a))$Var1, df$Var2, df$Var3, sep = "_"), magg_outer = outer(x, y, paste, sep = "_") %>% outer(z, paste, sep = "_") %>% outer(a, paste, sep = "_") %>% as.vector, magg_tidy = data.frame(x, y, z, a) %>% complete(x, y, z, a) %>% unite("combo", x, y, z, a, sep = "_"), interaction = levels(interaction(x, y, z, a, sep = "_")), original = apply(expand.grid(x, y, z, a), 1, paste, collapse = "_"), rep = paste(rep(x, each = (ny <- length(y)) * (nz <- length(z)) * (na <- length(a))), rep(rep(y, each = nz * na), (nx <- length(x))), rep(rep(z, each = na), nx * ny), sep = "_"), Reduce = Reduce(function(x, y) paste(rep(x, each = length(y)), rep(y, length(x)), sep = "_"), list(x, y, z, a)))
Benchmarking: large grid (1,000,000 elements)
set.seed(21034) x <- sprintf("%03d", sample(100)) y <- sprintf("%03d", sample(100)) z <- sprintf("%02d", sample(10)) a <- sprintf("%02d", sample(10)) library(data.table) library(microbenchmark) library(magrittr) library(tidyr) microbenchmark(times = 25L, DT1 = CJ(x, y, z, a)[ , paste(V1, V2, V3, V4, sep = "_")], DT2 = CJ(x, y, z, a)[ , do.call(paste, c(.SD, sep = "_"))], app1 = do.call(paste, c(expand.grid(x, y, z, a), sep = "_")), app2 = paste((df <- expand.grid(x, y, z, a))$Var1, df$Var2, df$Var3, sep = "_"), magg_outer = outer(x, y, paste, sep = "_") %>% outer(z, paste, sep = "_") %>% outer(a, paste, sep = "_") %>% as.vector, magg_tidy = data.frame(x, y, z, a) %>% complete(x, y, z, a) %>% unite("combo", x, y, z, a, sep = "_"), interaction = levels(interaction(x, y, z, a, sep = "_")), original = apply(expand.grid(x, y, z, a), 1, paste, collapse = "_"), rep = paste(rep(x, each = (ny <- length(y)) * (nz <- length(z)) * (na <- length(a))), rep(rep(y, each = nz * na), (nx <- length(x))), rep(rep(z, each = na), nx * ny), sep = "_"), Reduce = Reduce(function(x, y) paste(rep(x, each = length(y)), rep(y, length(x)), sep = "_"), list(x, y, z, a)))