How to get different combination in a character using R?

Viewed 78

This is my character "NGNG" , here N represents either of c("A", "T", "C", "G"), so in my output I need a total of 16 combinations such as AGAG, TGAG, CGAG, GGAG, TGTG, TGCG, TGGG and so on.

If it is only a single change at the start for example "NGG" I can easily do it with expand_grid from tidyr

library(tidyverse)
expand_grid(one = c("A", "T", "C", "G"), two = "NG") %>% 
  mutate(three = paste0(one, two)) %>% 
  pull(three)


[1] "ANG" "TNG" "CNG" "GNG"

But I'm struggling to find a way to do this when N comes in the middle or multiples of it.

2 Answers

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.

Here is a weird approach on how to achieve your desired output: Here are a few notes on this solution:

  • I wrapped map2 function around curly braces so I can choose .x and .y myself as %>% put the LHS (here a data frame) in the first argument
  • exec function applies a function on a list of arguments which acts more like do.call in base R and using !!! will splice elements of the resulting list so that each one become a single argument for then to be bound by rows
library(purrr)

N <- c("A", "T", "C", "G")

expand.grid(N, N) %>%
  {map2(.$Var1, .$Var2, ~ paste0(.x, "G", .y, "G"))} %>%
  exec(rbind, !!!.)

      [,1]  
 [1,] "AGAG"
 [2,] "TGAG"
 [3,] "CGAG"
 [4,] "GGAG"
 [5,] "AGTG"
 [6,] "TGTG"
 [7,] "CGTG"
 [8,] "GGTG"
 [9,] "AGCG"
[10,] "TGCG"
[11,] "CGCG"
[12,] "GGCG"
[13,] "AGGG"
[14,] "TGGG"
[15,] "CGGG"
[16,] "GGGG"
Related