【问题标题】:Remove repeating numbers from for loop从 for 循环中删除重复的数字
【发布时间】:2019-08-12 20:55:16
【问题描述】:

我在 R 中有以下代码(由 Mark -Finding all possible combinations of numbers to reach a given sum 发布),它允许我将数字添加到目标值。 但是,我希望代码返回所有可能的组合而不重复相同的数字,并将删除的数字存储在单独的列表中。我需要分配索引值吗?

x <- c(55,10,13,26,34,72,51,96,13)

subset_sum = function(numbers,target,partial=0){
  if(any(is.na(partial))) return()
  s = sum(partial)
  if(s > target) return()
  if(between(s,target-3,target)) print(sprintf("%s = %s",paste(partial[-1],collapse=" "),s))
  for(i in seq_along(numbers)){
      n = numbers[i]
      remaining = numbers[(i+1):length(numbers)]
      subset_sum(remaining,target,c(partial,n))
    }
}

subset_sum(x,60)

#The actual output is:
[1] "10 13 34 = 57"
[1] "26 34 = 60"

#I expect the output as (no repetition of 34):
[1] 26 34 = 60

提前致谢!

【问题讨论】:

  • 没有数字重复,这变得非常类似于装箱问题。调查这可能会有所帮助。
  • @Shree:谢谢指导,我会调查的!

标签: r recursion mathematical-optimization subset-sum bin-packing


【解决方案1】:

RcppAlgos(我是作者)是专门为这个任务而构建的。下面是一个利用comboGeneral 的解决方案,它用于生成有或没有重复的组合以及多集。我们还可以使用constraintFuncomparisonFunlimitConstraints 来限制输出:

library(RcppAlgos)
mySubsetSum <- function(x, myTarget, repeats = FALSE) {
    if (0 %in% x)
        x <- x[-which(x == 0)]

    if (repeats) {
        tbl <- table(x)
        vals <- as.numeric(names(tbl))
        myfreqs <- unname(tbl)
    } else {
        vals <- unique(x)
        myfreqs <- rep(1, length(vals))
    }

    ## Add zero length(vals) - 1 times
    myfreqs <- c(length(vals) - 1, myfreqs)
    vals <- c(0L, vals)

    combs <- comboGeneral(vals, length(vals), freqs = myfreqs, 
                          constraintFun = "sum", 
                          comparisonFun = "==", 
                          limitConstraints = myTarget)

    lapply(1:nrow(combs), function(x) combs[x, combs[x,] != 0])
}

mySubsetSum(x, 60)
[[1]]
[1] 26 34

mySubsetSum(x, 60, TRUE)
[[1]]
[1] 26 34

[[2]]
[1] 13 13 34

它写在C++ 中以获得最大速度。这是一个展示其效率的示例:

set.seed(42)
s <- sample(-50:50, 20)
s
[1]  42  43 -22  31  12  -1  19 -38  11  14  -9  41  33 -28 -10  30  38 -41 -11  -5

system.time(bigTest <- mySubsetSum(s, 170))
 user  system elapsed 
0.039   0.000   0.040

length(bigTest)
[1] 2135

## Over 1 million total combinations
comboCount(c(0, s), 20, freqs = c(19, rep(1, 20)))
[1] 1048575

这是bigTest的输出示例

bigTest[1:5]
[[1]]
[1] -41 -38 -28 -22 -10  -5  11  12  14  19  30  31  33  38  41  42  43

[[2]]
[1] -41 -38 -28 -22  -9  -5  -1  11  12  14  19  30  31  33  38  41  42  43

[[3]]
[1] -41 -38 -28 -22  -1  11  12  19  30  31  33  38  41  42  43

[[4]]
[1] -41 -38 -28 -11 -10  -5  12  14  19  30  31  33  38  41  42  43

[[5]]
[1] -41 -38 -28 -11  -9  -5  -1  12  14  19  30  31  33  38  41  42  43

## View the last 5 combinations
bigTest[length(bigTest) - 4:0]
[[1]]
[1] 12 14 31 33 38 42

[[2]]
[1] 14 19 30 31 33 43

[[3]]
[1] 11 12 14 19 30 41 43

[[4]]
[1] 11 12 14 19 31 41 42

[[5]]
[1] 11 12 14 19 33 38 43


all(sapply(bigTest, sum) == 170)
[1] TRUE

您还可以找到在某个范围之间求和的组合。看起来 OP 最初是有这种想法的,因为 OP 使用了来自dplyrbetween(至少我认为它来自dplyr)。

sumRange <- comboGeneral(c(0, s), 20, freqs = c(19, rep(1, 20)), 
                         constraintFun = "sum", 
                         comparisonFun = c(">", "<"), 
                         limitConstraints = c(155, 165))

all(rowSums(sumRange) > 155 & rowSums(sumRange) < 165)
[1] TRUE

【讨论】:

    猜你喜欢
    • 2019-03-14
    • 2013-09-26
    • 1970-01-01
    • 2014-06-28
    • 2023-01-25
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多