17
\$\begingroup\$

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?
  2. Is there anything smelly about this code?
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Jul 31, 2014 at 5:34
\$\endgroup\$

4 Answers 4

17
\$\begingroup\$

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" 
answered Jul 31, 2014 at 8:59
\$\endgroup\$
0
6
\$\begingroup\$

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
answered Jul 18, 2015 at 16:01
\$\endgroup\$
6
\$\begingroup\$

Well, it can be still useful now-a-days.

a=c('europe', 'asia')
b=c('co2', 'temperature')
c=c('min', 'max')
apply(expand.grid(a,b,c), 1, function(x) paste0(x, collapse="_"))

Output:

[1] "europe_co2_min" "asia_co2_min" "europe_temperature_min"
[4] "asia_temperature_min" "europe_co2_max" "asia_co2_max" 
[7] "europe_temperature_max" "asia_temperature_max"
Stephen Rauch
4,31412 gold badges24 silver badges36 bronze badges
answered Apr 26, 2020 at 19:55
\$\endgroup\$
0
\$\begingroup\$

Maybe someone will still be served. I modified one of the codes they provided here, to create a tablet, although I'm not sure it's the best way to do it. Perhaps someone with more experience can tell us.

a <- c("a","b","o")
comb <- apply(expand.grid(a,a), 1, function(x) paste0(x, collapse=","))
tb <- matrix(comb,ncol = length(a),nrow=length(a))
colnames(tb) <- a
row.names(tb) <- a

Returns:

 a b o
a a,a a,b a,c 
b b,a b,b b,o 
o o,a o,b o,o
Peilonrayz
44.4k7 gold badges80 silver badges157 bronze badges
answered Oct 22, 2021 at 23:04
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Hi Samuel, all content on Code Review must be in English. I have used Google Translate to convert your answer to English. \$\endgroup\$ Commented Oct 23, 2021 at 0:35
  • \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit to show what aspects of the question code prompted you to write this version, and in what ways it's an improvement over the original. It may be worth (re-)reading How to Answer. \$\endgroup\$ Commented Oct 23, 2021 at 7:55

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.