1) This solution uses only base R and only one invocation of combn
. It works by taking all combinations of 3 elements of c(group1, group2, "")
and keeping only the ones that have one element from group1 and 1 or 2 from group2. The "" elements are removed leaving the desired list of vectors. We also show how to optionally represent this as a matrix.
Define function ok
to be TRUE if there are ix
occurrences of elements of g
in h
and FALSE otherwise. Then define g
to return its argument without any "" components if there is one element from group1 and 1 or 2 from group2; otherwise, it returns NULL. Apply g
to all combinations of 3 elements of c(group1, group2, "")
. Then remove any zero length rows and return the list L
. Use that if you want a list of character vectors as the result.
If, rather than a list result, a matrix result is wanted then use the last line as well.
ok <- function(g, h, ix) sum(g %in% h) %in% ix
g <- function(x) if (ok(x, group1, 1) && ok(x, group2, 1:2)) x[nchar(x) > 0]
L <- Filter(length, combn(c(group1, group2, ""), 3, g, simplify = FALSE))
# next line is only if you want a matrix result
do.call("rbind", lapply(L, `[`, 1:3))
giving this matrix:
[,1] [,2] [,3]
[1,] "a" "c" "d"
[2,] "a" "c" "e"
[3,] "a" "c" NA
[4,] "a" "d" "e"
[5,] "a" "d" NA
[6,] "a" "e" NA
[7,] "b" "c" "d"
[8,] "b" "c" "e"
[9,] "b" "c" NA
[10,] "b" "d" "e"
[11,] "b" "d" NA
[12,] "b" "e" NA
1a) This could also be expressed in terms of pipes like this. g
is from above.
c(group1, group2, "z") |>
combn(3, g, simplify = FALSE) |>
Filter(f = length) |>
lapply(`[`, 1:3) |> # this & next line if matrix wanted
do.call(what = "rbind")
2) An approach using string manipulation is to paste each component of combn output together and then use str_count to filter it down to count the occurrences. This gives a character vector result or we could split that into a list using strsplit(res, "")
.
library(stringr)
cc <- combn(c(group1, group2, ""), 3, paste, collapse = "")
res <- cc[str_count(cc, "[ab]") == 1 & str_count(cc, "[cde]") %in% 1:2]
res
## [1] "acd" "ace" "ac" "ade" "ad" "ae" "bcd" "bce" "bc" "bde" "bd" "be"
simplify = FALSE
tocombn
, you can removeasplit
. If you adduse.names = FALSE
to...
inapply
, you can removelapply(result, unname)
. Cheers – Lakenyalaker