使用和约束生成排列

C. *_*aun 5 r permutation combinatorics

我有n可变长度的集合,并希望得到每个集合中项目的所有排列,其中总和在一定范围内.例如R我们可以这样做:

set1 <- c(10, 15, 20)
set2 <- c(8, 9)
set3 <- c(1, 2, 3, 4)

permutations <- expand.grid(set1, set2, set3)
permutations$sum <- rowSums(permutations)
final <- permutations[permutations$sum >= 25 & permutations$sum <= 29, ]

# final:
#    Var1 Var2 Var3 sum
# 3    20    8    1  29
# 5    15    9    1  25
# 8    15    8    2  25
# 11   15    9    2  26
# 14   15    8    3  26
# 17   15    9    3  27
# 20   15    8    4  27
# 23   15    9    4  28
Run Code Online (Sandbox Code Playgroud)

这适用于少数几组,但是随着更多或更多数组的快速(因子)增长.

是否有可能生成符合约束条件的排列,而无需计算所有可能性?

在这个例子中,没有包含10的最终组合set1,因为无论选择哪个其他数字,结果总和都会太小.这可能有助于减少问题的范围.例如,如果我知道min(set1) + max(set2) + max(set3) < 25 == TRUE,那么我可以确保不包含min(set1)在任何排列中.

我如何概括这一点,并使用约束来防止生成无效的排列?

r2e*_*ans 4

我认为你所要求的是相当具体的鞋拔子,不太可能“容易实施”(有效)。另一种看待它的方法是在运行实验时进行调节(假设这是试验设计)。

我写了一个lazyExpandGrid.R在概念上与lazy 类似的函数expand.grid,这意味着它不会预先评估所有可能的组合。如果需要,代码可以稍后插入到这个答案中,但是 github-gist 相当可靠(而且不短)。

使用它,您应该能够执行以下操作:

set1 <- c(10, 15, 20)
set2 <- c(8, 9)
set3 <- c(1, 2, 3, 4)

iter <- lazyExpandGrid(set1, set2, set3)

while (is.data.frame(item <- iter$nextItem())) {
  p <- sum(item)
  if (p < 25 || 29 < p) next
  print(item) # but really, do something more interesting here
}
#   Var1 Var2 Var3
# 3   20    8    1
#   Var1 Var2 Var3
# 5   15    9    1
#   Var1 Var2 Var3
# 8   15    8    2
#    Var1 Var2 Var3
# 11   15    9    2
#    Var1 Var2 Var3
# 14   15    8    3
#    Var1 Var2 Var3
# 17   15    9    3
#    Var1 Var2 Var3
# 20   15    8    4
#    Var1 Var2 Var3
# 23   15    9    4
Run Code Online (Sandbox Code Playgroud)

买者自负:该功能大部分可用,但肯定有一些方法可以改进。例如,使用is.data.frame(item <- iter$nextItem())是有效的isTruthy测试(名称来自shiny);目前它返回 1 行,data.frame直到没有剩余,然后返回FALSE。现在看来,这肯定是可以改进的,只是我没有这个需要。如果您有想法、错误等,请随时在 github gist 页面上发表评论。