我有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
对于少数几个集合来说这是好的,但是随着集合的数量越来越大或越来越多,它们会迅速(因子地)增长。
是否可以生成符合约束条件的排列,而无需计算所有可能性?
在此示例中,没有包含来自set1
的10的最终组合,因为无论选择哪个其他数字,结果总和都会太小。这可能有助于减少问题的范围。例如,如果我知道min(set1) + max(set2) + max(set3) < 25 == TRUE
,那么我可以确保不在任何排列中包含min(set1)
。
我如何概括这一点,并使用约束来防止产生无效的排列?
答案 0 :(得分:4)
我认为你要求的是特定的鞋角,并且不太可能“易于实施”(高效)。另一种看待它的方法是在进行实验时进行调节(假设这是试验设计)。
我写了一个lazyExpandGrid.R
,其概念与懒惰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
警告:这个功能大部分都可以使用,但肯定有一些方法可以改进。例如,使用is.data.frame(item <- iter$nextItem())
实际上是isTruthy
测试(来自shiny
的名称);目前它返回1行data.frame
,直到什么都没有,然后返回FALSE
。正如我现在看到的那样,这肯定会得到改善,我只是没有必要。如果您有想法,错误等,请随意在github gist页面上发表评论。