# Generating Cartesian product of strings in R

Sometimes I need to create character vectors like this one:

datanames <- c(
"europe_co2_min",
"europe_co2_max",
"europe_temperature_min",
"europe_temperature_max",
"asia_co2_min",
"asia_co2_max",
"asia_temperature_min",
"asia_temperature_max"
)


Notice that this is actually the Cartesian product of the character vectors joined together with a _:

c('europe', 'asia')
c('co2', 'temperature')
c('min', 'max')


I came up with this helper function:

combine <- function(..., prefix='', sep='_') {
combine.inner <- function(lx, ...) {
if (length(c(...)) > 0) {
sapply(sapply(lx, function(x) paste(x, combine.inner(...), sep=sep)), c)
} else {
lx
}
}
paste(prefix, combine.inner(...), sep='')
}


It handles arbitrary number of character vector parameters of arbitrary lengths. The prefix parameter is for convenience. It's similar to having a single element vector as the first parameter, except the common separator sep will not be applied after it.

1. Is there an easier way that exists in R and I missed?

Your approach is an example of good R code. However, there is a base function that allows creating a cartesian product of strings, interaction. This function creates a factor, and the levels are equivalent to the cartesian product.

Furthermore, instead of paste(..., sep = "") you can use paste0(...).

If you use these functions, your code will be much shorter:

combine <- function(..., prefix = "", sep = "_") {
paste0(prefix, levels(interaction(..., sep = sep)))
}


Examples:

s1 <- c('europe', 'asia')
s2 <- c('co2', 'temperature')
s3 <- c('min', 'max')

combine(s1)
# [1] "europe" "asia"
combine(s1, s2)
# [1] "europe_co2"         "europe_temperature" "asia_co2"           "asia_temperature"
combine(s1, s2, s3)
# [1] "europe_co2_min"         "europe_co2_max"         "europe_temperature_min"
# [4] "europe_temperature_max" "asia_co2_min"           "asia_co2_max"
# [7] "asia_temperature_min"   "asia_temperature_max"


You can use expand.grid:

a <- c('europe', 'asia')
b <- c('co2', 'temperature')
c <- c('min', 'max')
expand.grid(a, b, c)


Output:

    Var1        Var2 Var3
1 europe         co2  min
2   asia         co2  min
3 europe temperature  min
4   asia temperature  min
5 europe         co2  max
6   asia         co2  max
7 europe temperature  max
8   asia temperature  max