You can define the function of "cumulative paste" using Reduce :
cumpaste = function(x, .sep = " ") Reduce(function(x1, x2) paste(x1, x2, sep = .sep), x, accumulate = TRUE) cumpaste(letters[1:3], "; ")
Cycle
Reduce avoids the repeated concatenation of elements from the very beginning, as it lengthens the previous concatenation with the next element.
Its application by group:
ave(as.character(testdf$content), testdf$id, FUN = cumpaste) #[1] "A" "AB" "ABA" "B" "BC" "BCB"
Another idea would be to concatenate the entire vector at the beginning and then gradually substring :
cumpaste2 = function(x, .sep = " ") { concat = paste(x, collapse = .sep) substring(concat, 1L, cumsum(c(nchar(x[[1L]]), nchar(x[-1L]) + nchar(.sep)))) } cumpaste2(letters[1:3], " ;@-")
This also looks a bit faster:
set.seed(077) X = replicate(1e3, paste(sample(letters, sample(0:5, 1), TRUE), collapse = "")) identical(cumpaste(X, " --- "), cumpaste2(X, " --- ")) #[1] TRUE microbenchmark::microbenchmark(cumpaste(X, " --- "), cumpaste2(X, " --- "), times = 30) #Unit: milliseconds # expr min lq mean median uq max neval cld # cumpaste(X, " --- ") 21.19967 21.82295 26.47899 24.83196 30.34068 39.86275 30 b # cumpaste2(X, " --- ") 14.41291 14.92378 16.87865 16.03339 18.56703 23.22958 30 a
... which makes it cumpaste_faster .