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.
- Is there an easier way that exists in R and I missed?
- Is there anything smelly about this code?
4 Answers 4
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
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"
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
-
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\$2021年10月23日 00:35:35 +00:00Commented 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\$Toby Speight– Toby Speight2021年10月23日 07:55:42 +00:00Commented Oct 23, 2021 at 7:55