精明的读者会注意到这个问题可以简化为:“如何生成所有 2 的幂的成对排列?”通过这种方式查看,我们可以避免最初处理二进制向量并将其保存到最后一步。
使用基本R函数intToBits,this answer到问题How to convert integer numbers into binary vector?,以及任何可以生成特定长度排列的函数(有很多包:gtools::permutations,RcppAlgos::permuteGeneral,@ 987654326@, 和arrangements::permutations),我们可以在一行中得到想要的结果。
library(gtools)
t(sapply(t(gtools::permutations(3, 2, 2^(0:2))),
function(x) {as.integer(intToBits(x))})[1:3, ])
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 1 0
[3,] 1 0 0
[4,] 0 0 1
[5,] 0 1 0
[6,] 1 0 0
[7,] 0 1 0
[8,] 0 0 1
[9,] 0 0 1
[10,] 1 0 0
[11,] 0 0 1
[12,] 0 1 0
概括很容易。
bitPairwise <- function(numBits, groupSize) {
t(sapply(t(gtools::permutations(numBits, groupSize, 2^(0:(numBits-1)))),
function(x) {as.integer(intToBits(x))})[1:numBits, ])
}
bitPairwise(numBits = 6, groupSize = 3)[1:12, ]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 0 0 0 0
[2,] 0 1 0 0 0 0
[3,] 0 0 1 0 0 0
[4,] 1 0 0 0 0 0
[5,] 0 1 0 0 0 0
[6,] 0 0 0 1 0 0
[7,] 1 0 0 0 0 0
[8,] 0 1 0 0 0 0
[9,] 0 0 0 0 1 0
[10,] 1 0 0 0 0 0
[11,] 0 1 0 0 0 0
[12,] 0 0 0 0 0 1
更新
我发布此内容只是为了指出@Suren 的答案如何正确。
OP 正在寻找排列而不是组合
从 cmets 中的对话中,您会看到 @Suren 的解决方案在组数增加时没有给出正确的结果(“我还试图获得三个而不是 2 个(或任何数字)的分组" 和 "这正在切断一些解决方案")。
看来@Suren 的答案使用g = 2 给出了正确的结果。之所以如此,是因为1:n choose 2 的排列等于1:n choose 2 与n:1 choose 2 组合的组合(注意1:n 是相反的)。这正是@Suren 的答案正在做的事情(即生成组合选择 2,以相反的顺序编写它们,然后组合)。
## original version
surenFun <- function(n, g) {
m <- combn(n, g)
mm <- as.numeric(m)
mat <- matrix(0, nrow = g * ncol(m), ncol = n)
mat[ cbind(1:nrow(mat), mm)] <- 1
soln <- rbind(mat, mat[nrow(mat):1, ])
split(data.frame(soln), rep(1:(nrow(soln)/g), each=g))
}
## Here is the corrected version
surenFunCorrected <- function(n, g) {
## changed combn to gtools::permutations or any other
## similar function that can generate permutations
m <- gtools::permutations(n, g)
## you must transpose m
mm <- as.numeric(t(m))
## change ncol(m) to nrow(m)
mat <- matrix(0, nrow = g * nrow(m), ncol = n)
mat[ cbind(1:nrow(mat), mm)] <- 1
## removed soln
split(data.frame(mat), rep(1:(nrow(mat)/g), each=g))
}
使用 OP 中的给定示例,它会以不同的顺序给出相同的结果:
## The order is slightly different
match(surenFunCorrected(3, 2), surenFun(3, 2))
[1] 1 2 6 3 5 4
all(surenFunCorrected(3, 2) %in% surenFun(3, 2))
[1] TRUE
all(surenFun(3, 2) %in% surenFunCorrected(3, 2))
[1] TRUE
让我们用g = 3 和n = 4 来测试一下。
## N.B. all of the original output is
## contained in the corrected output
all(surenFun(4, 3) %in% surenFunCorrected(4, 3))
[1] TRUE
## However, there are 16 results
## not returned in the original
leftOut <- which(!(surenFunCorrected(4, 3) %in% surenFun(4, 3)))
leftOut
[1] 3 5 6 7 8 9 11 12 13 14 16 17 18 19 20 22
## E.g. 3 examples that were left out
surenFunCorrected(4, 3)[leftOut[c(1,8,16)]]
$`3`
X1 X2 X3 X4
7 1 0 0 0
8 0 0 1 0
9 0 1 0 0
$`12`
X1 X2 X3 X4
34 0 1 0 0
35 0 0 0 1
36 0 0 1 0
$`22`
X1 X2 X3 X4
64 0 0 0 1
65 0 1 0 0
66 0 0 1 0