一一绘制二元向量的条件组合
Drawing conditional combinations of a binary vector one by one
我正在尝试编写一个例程来有条件地查找二元向量的组合。例如,考虑以下向量:
> A <- rep(c(1,0,0),3)
> A
[1] 1 0 0 1 0 0 1 0 0
注意,向量A的长度总是3的倍数,所以下面的条件总是成立:
length(A) %% 3 == 0
主要条件是每组连续的3个向量中必须只有一个1。在这个例子中,比如A[1:3]的一个元素为1,A[4:6]的一个元素为1,A[7:9]的一个元素为1,其余都是0. 因此,对于这个例子,总共会有27种可能的组合。
Objective就是套路draw/return下一个有效组合,直到返回所有可能的合法组合。
请注意,我不是在寻找具有所有可能组合的 table。 已在我在 Whosebug 中的其他查询中可用。但是,使用该方法,当 A 中超过 45 个元素的长度时,我 运行 陷入内存问题,因为它返回的是巨大的完整矩阵。因此,我不想存储完整的矩阵,而是想一次检索一个组合,然后再决定是否要存储它。
OP追求的是一个迭代器。如果我们要正确地做到这一点,我们将使用 get_next
方法在 C++
中编写一个 class,并将其公开给 R
。就目前而言,对于基础 R,由于一切都是按值传递的,我们必须在我们的待更新对象上调用一个函数,并且每次都重新分配要更新的对象。
这是一个非常粗略的实现:
get_next <- function(comb, v, m) {
s <- seq(1L, length(comb), length(v))
e <- seq(length(v), length(comb), length(v))
last_comb <- rev(v)
can_be_incr <- sapply(seq_len(m), function(x) {
!identical(comb[s[x]:e[x]], last_comb)
})
if (all(!can_be_incr)) {
return(FALSE)
} else {
idx <- which(can_be_incr)[1L]
span <- s[idx]:e[idx]
j <- which(comb[span] == 1L)
comb[span[j]] <- 0L
comb[span[j + 1L]] <- 1L
if (idx > 1L) {
## Reset previous maxed out sections
for (i in 1:(idx - 1L)) {
comb[s[i]:e[i]] <- v
}
}
}
return(comb)
}
这是一个简单的用法:
m <- 3L
v <- as.integer(c(1,0,0))
comb <- rep(v, m)
count <- 1L
while (!is.logical(comb)) {
cat(count, ": ", comb, "\n")
comb <- get_next(comb, v, m)
count <- count + 1L
}
1 : 1 0 0 1 0 0 1 0 0
2 : 0 1 0 1 0 0 1 0 0
3 : 0 0 1 1 0 0 1 0 0
4 : 1 0 0 0 1 0 1 0 0
5 : 0 1 0 0 1 0 1 0 0
6 : 0 0 1 0 1 0 1 0 0
7 : 1 0 0 0 0 1 1 0 0
8 : 0 1 0 0 0 1 1 0 0
9 : 0 0 1 0 0 1 1 0 0
10 : 1 0 0 1 0 0 0 1 0
11 : 0 1 0 1 0 0 0 1 0
12 : 0 0 1 1 0 0 0 1 0
13 : 1 0 0 0 1 0 0 1 0
14 : 0 1 0 0 1 0 0 1 0
15 : 0 0 1 0 1 0 0 1 0
16 : 1 0 0 0 0 1 0 1 0
17 : 0 1 0 0 0 1 0 1 0
18 : 0 0 1 0 0 1 0 1 0
19 : 1 0 0 1 0 0 0 0 1
20 : 0 1 0 1 0 0 0 0 1
21 : 0 0 1 1 0 0 0 0 1
22 : 1 0 0 0 1 0 0 0 1
23 : 0 1 0 0 1 0 0 0 1
24 : 0 0 1 0 1 0 0 0 1
25 : 1 0 0 0 0 1 0 0 1
26 : 0 1 0 0 0 1 0 0 1
27 : 0 0 1 0 0 1 0 0 1
请注意,此实现将提高内存效率,但速度会很慢。
我正在尝试编写一个例程来有条件地查找二元向量的组合。例如,考虑以下向量:
> A <- rep(c(1,0,0),3)
> A
[1] 1 0 0 1 0 0 1 0 0
注意,向量A的长度总是3的倍数,所以下面的条件总是成立:
length(A) %% 3 == 0
主要条件是每组连续的3个向量中必须只有一个1。在这个例子中,比如A[1:3]的一个元素为1,A[4:6]的一个元素为1,A[7:9]的一个元素为1,其余都是0. 因此,对于这个例子,总共会有27种可能的组合。
Objective就是套路draw/return下一个有效组合,直到返回所有可能的合法组合。
请注意,我不是在寻找具有所有可能组合的 table。
OP追求的是一个迭代器。如果我们要正确地做到这一点,我们将使用 get_next
方法在 C++
中编写一个 class,并将其公开给 R
。就目前而言,对于基础 R,由于一切都是按值传递的,我们必须在我们的待更新对象上调用一个函数,并且每次都重新分配要更新的对象。
这是一个非常粗略的实现:
get_next <- function(comb, v, m) {
s <- seq(1L, length(comb), length(v))
e <- seq(length(v), length(comb), length(v))
last_comb <- rev(v)
can_be_incr <- sapply(seq_len(m), function(x) {
!identical(comb[s[x]:e[x]], last_comb)
})
if (all(!can_be_incr)) {
return(FALSE)
} else {
idx <- which(can_be_incr)[1L]
span <- s[idx]:e[idx]
j <- which(comb[span] == 1L)
comb[span[j]] <- 0L
comb[span[j + 1L]] <- 1L
if (idx > 1L) {
## Reset previous maxed out sections
for (i in 1:(idx - 1L)) {
comb[s[i]:e[i]] <- v
}
}
}
return(comb)
}
这是一个简单的用法:
m <- 3L
v <- as.integer(c(1,0,0))
comb <- rep(v, m)
count <- 1L
while (!is.logical(comb)) {
cat(count, ": ", comb, "\n")
comb <- get_next(comb, v, m)
count <- count + 1L
}
1 : 1 0 0 1 0 0 1 0 0
2 : 0 1 0 1 0 0 1 0 0
3 : 0 0 1 1 0 0 1 0 0
4 : 1 0 0 0 1 0 1 0 0
5 : 0 1 0 0 1 0 1 0 0
6 : 0 0 1 0 1 0 1 0 0
7 : 1 0 0 0 0 1 1 0 0
8 : 0 1 0 0 0 1 1 0 0
9 : 0 0 1 0 0 1 1 0 0
10 : 1 0 0 1 0 0 0 1 0
11 : 0 1 0 1 0 0 0 1 0
12 : 0 0 1 1 0 0 0 1 0
13 : 1 0 0 0 1 0 0 1 0
14 : 0 1 0 0 1 0 0 1 0
15 : 0 0 1 0 1 0 0 1 0
16 : 1 0 0 0 0 1 0 1 0
17 : 0 1 0 0 0 1 0 1 0
18 : 0 0 1 0 0 1 0 1 0
19 : 1 0 0 1 0 0 0 0 1
20 : 0 1 0 1 0 0 0 0 1
21 : 0 0 1 1 0 0 0 0 1
22 : 1 0 0 0 1 0 0 0 1
23 : 0 1 0 0 1 0 0 0 1
24 : 0 0 1 0 1 0 0 0 1
25 : 1 0 0 0 0 1 0 0 1
26 : 0 1 0 0 0 1 0 0 1
27 : 0 0 1 0 0 1 0 0 1
请注意,此实现将提高内存效率,但速度会很慢。