Generating Cartesian product of strings in R Sometimes I need to create character vectors like this one:

datanames &lt;- 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 &lt;- function(..., prefix='', sep='_') {
  combine.inner &lt;- function(lx, ...) {
    if (length(c(...)) &gt; 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.


Is there an easier way that exists in R and I missed?
Is there anything smelly about this code?
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 &lt;- function(..., prefix = "", sep = "_") {
  paste0(prefix, levels(interaction(..., sep = sep)))
}


Examples:

s1 &lt;- c('europe', 'asia')
s2 &lt;- c('co2', 'temperature')
s3 &lt;- 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"