HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Generating Cartesian product of strings in R

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
generatingstringscartesianproduct

Problem

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  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?

Solution

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"

Code Snippets

combine <- function(..., prefix = "", sep = "_") {
  paste0(prefix, levels(interaction(..., sep = sep)))
}
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"

Context

StackExchange Code Review Q#58595, answer score: 17

Revisions (0)

No revisions yet.