这是另一个尝试。它不使用sample
,但使用runif
. 我在显示总和的输出中添加了一个可选的“消息”,可以使用showSum
参数触发。还有一个Tolerance
参数指定需要多接近目标。
SampleToSum <- function(Target = 100, VecLen = 10,
InRange = 1:100, Tolerance = 2,
showSum = TRUE) {
Res <- vector()
while ( TRUE ) {
Res <- round(diff(c(0, sort(runif(VecLen - 1)), 1)) * Target)
if ( all(Res > 0) &
all(Res >= min(InRange)) &
all(Res <= max(InRange)) &
abs((sum(Res) - Target)) <= Tolerance ) { break }
}
if (isTRUE(showSum)) cat("Total = ", sum(Res), "\n")
Res
}
这里有些例子。
注意默认设置和设置之间的区别Tolerance = 0
set.seed(1)
SampleToSum()
# Total = 101
# [1] 20 6 11 20 6 3 24 1 4 6
SampleToSum(Tolerance=0)
# Total = 100
# [1] 19 15 4 10 1 11 7 16 4 13
您可以使用 来验证此行为replicate
。这是设置Tolerance = 0
和运行函数 5 次的结果。
system.time(output <- replicate(5, SampleToSum(
Target = 1376,
VecLen = 13,
InRange = 10:200,
Tolerance = 0)))
# Total = 1376
# Total = 1376
# Total = 1376
# Total = 1376
# Total = 1376
# user system elapsed
# 0.144 0.000 0.145
output
# [,1] [,2] [,3] [,4] [,5]
# [1,] 29 46 11 43 171
# [2,] 103 161 113 195 197
# [3,] 145 134 91 131 147
# [4,] 154 173 138 19 17
# [5,] 197 62 173 11 87
# [6,] 101 142 87 173 99
# [7,] 168 61 97 40 121
# [8,] 140 121 99 135 117
# [9,] 46 78 31 200 79
# [10,] 140 168 146 17 56
# [11,] 21 146 117 182 85
# [12,] 63 30 180 179 78
# [13,] 69 54 93 51 122
设置Tolerance = 5
和运行该功能5次也是如此。
system.time(output <- replicate(5, SampleToSum(
Target = 1376,
VecLen = 13,
InRange = 10:200,
Tolerance = 5)))
# Total = 1375
# Total = 1376
# Total = 1374
# Total = 1374
# Total = 1376
# user system elapsed
# 0.060 0.000 0.058
output
# [,1] [,2] [,3] [,4] [,5]
# [1,] 65 190 103 15 47
# [2,] 160 95 98 196 183
# [3,] 178 169 134 15 26
# [4,] 49 53 186 48 41
# [5,] 104 81 161 171 180
# [6,] 54 126 67 130 182
# [7,] 34 131 49 113 76
# [8,] 17 21 107 62 95
# [9,] 151 136 132 195 169
# [10,] 194 187 91 163 22
# [11,] 23 69 54 97 30
# [12,] 190 14 134 43 150
# [13,] 156 104 58 126 175
毫不奇怪,将容差设置为 0 会使函数变慢。
速度(或缺乏)
请注意,由于这是一个“随机”过程,因此很难猜测找到正确的数字组合需要多长时间。例如,使用set.seed(123)
,我连续运行了 3 次以下测试:
system.time(SampleToSum(Target = 1163,
VecLen = 15,
InRange = 50:150))
第一次运行只用了 9 秒多一点。第二次只用了 7.5 秒多一点。第三个用时……不到 381 秒!这是很多变化!
出于好奇,我在函数中添加了一个计数器,第一次运行尝试了55026次,以达到满足我们所有条件的向量!(我没有费心尝试第二次和第三次尝试。)
在函数中添加一些错误或健全性检查以确保输入是合理的可能会很好。例如,一个人不应该能够输入SampleToSum(Target = 100, VecLen = 10, InRange = 15:50)
,因为在 15 到 50 的范围内,没有办法达到 100 并且向量中有 10 个值。