A `tidyverse` way starting from your original data `dat` :
```
library(tidyverse)
n <- 4
dat %>%
uncount(n) %>%
group_by(ID) %>%
mutate(Ind = row_number()) %>%
ungroup() %>%
mutate(Ind2 = as.integer(Con == Ind)) -> dat2
bind_cols(dat2, map_dfc(seq_len(n),
~dat2 %>% transmute(!!paste0('Cond', .x) := as.integer(Ind == .x))))
# ID Con An Bc Dd Kl Fp Ind Ind2 Cond1 Cond2 Cond3 Cond4
# <chr> <int> <int> <int> <int> <int> <chr> <int> <int> <int> <int> <int> <int>
# 1 a1 1 1 1 1 10 3 1 1 1 0 0 0
# 2 a1 1 1 1 1 10 3 2 0 0 1 0 0
# 3 a1 1 1 1 1 10 3 3 0 0 0 1 0
# 4 a1 1 1 1 1 10 3 4 0 0 0 0 1
# 5 a2 3 1 0 0 11 4 1 0 1 0 0 0
# 6 a2 3 1 0 0 11 4 2 0 0 1 0 0
# 7 a2 3 1 0 0 11 4 3 1 0 0 1 0
# 8 a2 3 1 0 0 11 4 4 0 0 0 0 1
# 9 a3 4 0 0 0 12 a6 1 0 1 0 0 0
#10 a3 4 0 0 0 12 a6 2 0 0 1 0 0
# … with 14 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