How about expand.grid followed by do.call?
cart_prod <- expand.grid(c("A", "T", "C", "G"),
"G",
c("A", "T", "C", "G"),
"G")
do.call(paste0, cart_prod)
[1] "AGAG" "TGAG" "CGAG" "GGAG" "AGTG" "TGTG" "CGTG" "GGTG"
[9] "AGCG" "TGCG" "CGCG" "GGCG" "AGGG" "TGGG" "CGGG" "GGGG"
Explanation
Since the OP requested that index 2 and 4 remain as "G", we simply let the first 1st and 3rd argument vary over the possible choices: c("A", "T", "C", "G"). Now, calling expand.grid with the first 4 arguments as:
c("A", "T", "C", "G")
"G"
c("A", "T", "C", "G")
"G"
will produce a data.frame that is isomorphic to our desired result, since expand.grid returns the Cartesian product.
expand.grid(c("A", "T", "C", "G"),
"G",
c("A", "T", "C", "G"),
"G")
Var1 Var2 Var3 Var4
1 A G A G
2 T G A G
3 C G A G
4 G G A G
5 A G T G
6 T G T G
7 C G T G
8 G G T G
9 A G C G
10 T G C G
11 C G C G
12 G G C G
13 A G G G
14 T G G G
15 C G G G
16 G G G G
Now, all that is left is smashing the columns together. We make use of do.call and paste0 to achieve this.
Why does do.call(paste0, some_data.frame) Work?
I found this great explanation on do.call here: The {do.call} function. Here is the first line:
"R has an interesting function called do.call. This function allows you to call any R function, but instead of writing out the arguments one by one, you can use a list to hold the arguments of the function."
Since a data.frame is essentially a list under the hood, we can utilize do.call in the usual way.
Since each column of cart_prod is simply a vector, paste0 combines each column element-wise. For example, the first and second column are:
cart_prod$Var1
[1] A T C G A T C G A T C G A T C G
Levels: A T C G
cart_prod$Var2
[1] G G G G G G G G G G G G G G G G
Levels: G
Applying paste0 to these two, gives:
paste0(cart_prod$Var1, cart_prod$Var2)
[1] "AG" "TG" "CG" "GG" "AG" "TG" "CG" "GG"
[9] "AG" "TG" "CG" "GG" "AG" "TG" "CG" "GG"
As you can see, we are starting to see our desired result come together. If we were to combine this result with the third column, we would obtain:
paste0(paste0(cart_prod$Var1, cart_prod$Var2), cart_prod$Var3)
[1] "AGA" "TGA" "CGA" "GGA" "AGT" "TGT" "CGT" "GGT"
[9] "AGC" "TGC" "CGC" "GGC" "AGG" "TGG" "CGG" "GGG"
And now, we combine this result with the last column:
paste0(paste0(paste0(cart_prod$Var1, cart_prod$Var2), cart_prod$Var3), cart_prod$Var4)
[1] "AGAG" "TGAG" "CGAG" "GGAG" "AGTG" "TGTG" "CGTG" "GGTG"
[9] "AGCG" "TGCG" "CGCG" "GGCG" "AGGG" "TGGG" "CGGG" "GGGG"
Voila! We have our desired result.