简体   繁体   中英

R - generate all combinations from 2 vectors given constraints

I would like to generate all combinations of two vectors, given two constraints: there can never be more than 3 characters from the first vector, and there must always be at least one characters from the second vector. I would also like to vary the final number of characters in the combination.

For instance, here are two vectors:

vec1=c("A","B","C","D")
vec2=c("W","X","Y","Z")

Say I wanted 3 characters in the combination. Possible acceptable permutations would be: "A" "B" "X" or "A" "Y" "Z" . An unacceptable permutation would be: "A" "B" "C" since there is not at least one character from vec2 .

Now say I wanted 5 characters in the combination. Possible acceptable permutations would be: "A" "C" "Z" "Y" or "A" "Y" "Z" "X" . An unacceptable permutation would be: "A" "C" "D" "B" "X" since there are >3 characters from vec2 .

I suppose I could use expand.grid to generate all combinations and then somehow subset, but there must be an easier way. Thanks in advance!

I'm not sure wheter this is easier, but you can leave away permutations that do not satisfy your conditions whith this strategy:

  1. generate all combinations from vec1 that are acceptable.

  2. generate all combinations from vec2 that are acceptable.

  3. generate all combinations taking one solution from 1. + one solution from 2. Here I'd do the filtering with condition 3 afterwards.

  4. (if you're looking for combinations, you're done, otherwise:) produce all permutations of letters within each result.

Now, let's have

vec1 <- LETTERS [1:4]
vec2 <- LETTERS [23:26]

## lists can eat up lots of memory, so use character vectors instead.
combine <- function (x, y) 
  combn (y, x, paste, collapse = "")

res1 <- unlist (lapply (0:3, combine, vec1))
res2 <- unlist (lapply (1:length (vec2), combine, vec2))

now we have:

> res1
 [1] ""    "A"   "B"   "C"   "D"   "AB"  "AC"  "AD"  "BC"  "BD"  "CD"  "ABC"
[13] "ABD" "ACD" "BCD"
> res2
 [1] "W"    "X"    "Y"    "Z"    "WX"   "WY"   "WZ"   "XY"   "XZ"   "YZ"  
[11] "WXY"  "WXZ"  "WYZ"  "XYZ"  "WXYZ"

res3 <- outer (res1, res2, paste0)
res3 <- res3 [nchar (res3) == 5]

So here you are:

> res3
 [1] "ABCWX" "ABDWX" "ACDWX" "BCDWX" "ABCWY" "ABDWY" "ACDWY" "BCDWY" "ABCWZ"
[10] "ABDWZ" "ACDWZ" "BCDWZ" "ABCXY" "ABDXY" "ACDXY" "BCDXY" "ABCXZ" "ABDXZ"
[19] "ACDXZ" "BCDXZ" "ABCYZ" "ABDYZ" "ACDYZ" "BCDYZ" "ABWXY" "ACWXY" "ADWXY"
[28] "BCWXY" "BDWXY" "CDWXY" "ABWXZ" "ACWXZ" "ADWXZ" "BCWXZ" "BDWXZ" "CDWXZ"
[37] "ABWYZ" "ACWYZ" "ADWYZ" "BCWYZ" "BDWYZ" "CDWYZ" "ABXYZ" "ACXYZ" "ADXYZ"
[46] "BCXYZ" "BDXYZ" "CDXYZ" "AWXYZ" "BWXYZ" "CWXYZ" "DWXYZ"

If you prefer the results split into single letters:

res <- matrix (unlist (strsplit (res3, "")), nrow = length (res3), byrow = TRUE)
> res
      [,1] [,2] [,3] [,4] [,5]
 [1,] "A"  "B"  "C"  "W"  "X" 
 [2,] "A"  "B"  "D"  "W"  "X" 
 [3,] "A"  "C"  "D"  "W"  "X" 
 [4,] "B"  "C"  "D"  "W"  "X" 

(snip)

[51,] "C"  "W"  "X"  "Y"  "Z" 
[52,] "D"  "W"  "X"  "Y"  "Z" 

Which are your combinations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM