组合部分和

时间:2014-05-31 19:02:09

标签: r numbers combinatorics

我正在R寻找一个函数partial.sum(),它接受​​一个数字向量并返回所有部分和的升序排序向量:

test=c(2,5,10)
partial.sum(test)

# 2 5 7 10 12 15 17
## 2 is the sum of element 2
## 5 is the sum of element 5    
## 7 is the sum of elements 2 & 5    
## 10 is the sum of element 10    
## 12 is the sum of elements 2 & 10    
## 15 is the sum of elements 5 & 10
## 17 is the sum of elements 2 & 5 & 10

3 个答案:

答案 0 :(得分:6)

这是一个使用递归。 (不要声称它有效率)

partial.sum <- function(x) {
   slave <- function(x) {
      if (length(x)) {
         y <- Recall(x[-1])
         c(y + 0, y + x[1])
      } else 0
   }
   sort(unique(slave(x)[-1]))
}

partial.sum(c(2,5,10))
# [1]  2  5  7 10 12 15 17

编辑:好吧,事实证明它比我想象的要快一点:

x <- 1:20
microbenchmark(flodel(x), dason(x), matthew(x), times = 10)
# Unit: milliseconds
#        expr        min        lq     median        uq       max neval
#   flodel(x)   86.31128   86.9966   94.12023  125.1013  163.5824    10
#    dason(x) 2407.27062 2461.2022 2633.73003 2846.2639 3031.7250    10
#  matthew(x) 3084.59227 3191.7810 3304.36064 3693.8595 3883.2767    10

(我已将sort和/或unique添加到dason和matthew的职能部门,以便进行公平比较。)

答案 1 :(得分:3)

这可能不会很好地扩展,并且不会考虑输入向量中的可能重复或答案中的重复。如果您担心这一点,可以稍后使用unique

partial.sum <- function(x){
  n <- length(x)
  # Something that will help get us every possible subset
  # of the original vector
  out <- do.call(expand.grid, replicate(n, c(T,F), simplify = F))
  # Don't include the case where we don't grab any elements
  out <- head(out, -1)

  # ans <- apply(out, 1, function(row){sum(x[row])})
  # As flodel points out the following will be faster than
  # the previous line
  ans <- data.matrix(out) %*% x
  # If you want only unique value then add a call to unique here
  ans <- sort(unname(ans))
  ans
}

答案 2 :(得分:2)

这是一种使用combn生成求和组合的迭代方法。它适用于长度大于1的矢量。

partial.sum <- function(x) {
  sort(unique(unlist(sapply(seq_along(x), function(i) colSums(combn(x,i))))))
}
## [1]  2  5  7 10 12 15 17

要处理小于2的长度,请测试长度:

partial.sum <- function(x) {
  if (length(x) > 1) {
    sort(unique(unlist(sapply(seq_along(x), function(i) colSums(combn(x,i))))))
  } else {
    x
  }
}

rbenchmark中的一些时间,不完全同意弗洛尔德的结果。我修改了Dason的代码,删除了评论并添加了对unique的调用。我的代码版本是第一个,没有if。 flodel的代码在这里是一个明显的赢家。

> test <- 1:10
> benchmark(matthew(test), flodel(test), dason(test), replications=100)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)          100   0.180   12.857     0.175    0.004          0         0
2  flodel(test)          100   0.014    1.000     0.015    0.000          0         0
1 matthew(test)          100   0.244   17.429     0.242    0.001          0         0

> test <- 1:20
> benchmark(matthew(test), flodel(test), dason(test), replications=1)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)            1   5.231   98.698     5.158    0.058          0         0
2  flodel(test)            1   0.053    1.000     0.053    0.000          0         0
1 matthew(test)            1   2.184   41.208     2.180    0.000          0         0

> test <- 1:25
> benchmark(matthew(test), flodel(test), dason(test), replications=1)
           test replications elapsed relative user.self sys.self user.child sys.child
3   dason(test)            1 288.957  163.345   264.068   23.859          0         0
2  flodel(test)            1   1.769    1.000     1.727    0.038          0         0
1 matthew(test)            1  75.712   42.799    74.745    0.847          0         0