Here is a `purrr::map` alternative
bind_cols(
df,
map_dfc(c("col_1", "col_2"), function(i) map_dfc(c(1, 2), function(n)
df %>%
transmute(!!paste0(i, "_lag_", n, collapse = "") := lag(!!rlang::sym(i), n = n, by = time_col)))))
## A tibble: 26 x 7
# time_col col_1 col_2 col_1_lag_1 col_1_lag_2 col_2_lag_1 col_2_lag_2
# <int> <chr> <chr> <chr> <chr> <chr> <chr>
# 1 1 a z NA NA NA NA
# 2 2 b y a NA z NA
# 3 3 c x b a y z
# 4 4 d w c b x y
# 5 5 e v d c w x
# 6 6 f u e d v w
# 7 7 g t f e u v
# 8 8 h s g f t u
# 9 9 i r h g s t
#10 10 j q i h r s
## ... with 16 more rows
Just out of curiosity I've taken a look at what happens under the hood, and I've used [dtruss/strace][1] on each test.
C++
./a.out < in
Saw 6512403 lines in 8 seconds. Crunch speed: 814050
syscalls `sudo dtruss -c ./a.out < in`
CALL COUNT
__mac_syscall 1
<snip>
open 6
pread 8
mprotect 17
mmap 22
stat64 30
read_nocancel 25958
Python
./a.py < in
Read 6512402 lines in 1 seconds. LPS: 6512402
syscalls `sudo dtruss -c ./a.py < in`
CALL COUNT
__mac_syscall 1
<snip>
open 5
pread 8
mprotect 17
mmap 21
stat64 29
[1]: http://en.wikipedia.org/wiki/Strace