0

I am wondering if there is a generic way in R to create character vectors from a template where the values of another vector are expanded in an arbitrary number of times.

That is, I am looking for a function like tq84(template, vec) that I could call with tq84('foo_%d, bar_%d, baz_%d', 1:2) and then results in the vector "foo_1, bar_1, baz_1", "foo_2, bar_2, baz_2". Note that the length of the resulting vector should be equal to the length of the input vector.

René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293
  • perhaps with `rep` `paste(c("foo", "bar", "baz"), rep(1:2, each = 3), sep="_")` – akrun Jul 19 '19 at 14:18
  • @akrun, this would not be an arbitrary solution like I am after because I have to know the amount of percent signs and the format of the template when I am writing the `paste(...rep(...` line. – René Nyffenegger Jul 19 '19 at 14:22
  • 1
    Relevant: [Pasting two vectors with combinations of all vectors' elements](https://stackoverflow.com/questions/16143700/pasting-two-vectors-with-combinations-of-all-vectors-elements) – markus Jul 19 '19 at 16:26

3 Answers3

2

May be we can use the rep

tq84 <- function(template, vec) {
             paste(template, rep(vec, each = length(template)), sep="_")
 }
v1 <- c("foo", "bar", "baz")
tq84(v1, 1:2)
#[1] "foo_1" "bar_1" "baz_1" "foo_2" "bar_2" "baz_2"

If we need a single string that exactly matches the expected output

tq84n <- function(template, vec) {
       sapply(as.list(vec), function(x) paste(template, x, sep="_",
          collapse=" "))
 }
tq84n(v1, 1:2)
#[1] "foo_1 bar_1 baz_1" "foo_2 bar_2 baz_2"

Or another option is to use crossing and then do a group_by paste

library(tidyverse)
tq84n2 <- function(template, vec) {
     crossing(template, grp = vec) %>% 
         unite(template, template, grp, remove = FALSE) %>%
          group_by(grp) %>%
          summarise(template = str_c(template, collapse=" ")) %>%
          pull(template)
  }
tq84n2(v1, 1:2)
#[1] "bar_1 baz_1 foo_1" "bar_2 baz_2 foo_2"
akrun
  • 874,273
  • 37
  • 540
  • 662
1

Maybe , we can use outer with paste

vec <- c("foo", "bar", "vec")
c(outer(vec, 1:2, paste, sep = "_"))
#[1] "foo_1" "bar_1" "vec_1" "foo_2" "bar_2" "vec_2"

Or if you want to keep them separate we can skip c

outer(vec, 1:2, paste, sep = "_")

#        [,1]    [,2]   
#[1,] "foo_1" "foo_2"
#[2,] "bar_1" "bar_2"
#[3,] "vec_1" "vec_2"

Or to exactly match the expected output

apply(outer(vec, 1:2, paste, sep = "_"), 2, paste, collapse = ", ") 
#[1] "foo_1, bar_1, vec_1" "foo_2, bar_2, vec_2"
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
1

A Map alternative that returns a list:

     tq84 <- function(vec, numbers){
   Map(function(x)
     paste0(vec[x],"_",numbers),
     seq_along(vec))
 }
 foobar <- c("foo","bar","baz")
 tq84(foobar,1:2)
[[1]]
[1] "foo_1" "foo_2"

[[2]]
[1] "bar_1" "bar_2"

[[3]]
[1] "baz_1" "baz_2"
NelsonGon
  • 13,015
  • 7
  • 27
  • 57