我需要用N个随机数填充Ruby数组。但是,我需要确保它们彼此分开X个数字。
例如,我需要填充一个包含5个数字的数组,随机生成1到100之间的数字,但要确保没有数字比3更接近。
所以这是有效的:
[1, 4, 7, 22, 84] # the differences between the numbers are >= 3
这是无效的:
[1, 2, 50, 70, 90] # "1" and "2" are too close together
有什么想法吗?
答案 0 :(得分:3)
这是一个想法:每次生成一个随机数时,从候选者中删除与其接近的每个数字:
def gen_rand_arr(arr, diff)
sample = arr.sample
arr.delete_if {|x| (x - sample).abs < diff }
sample
end
然后使用它:
arr = (1..100).to_a
result = []
1.upto(5) { result << gen_rand_arr(arr, 3) }
p result.sort
答案 1 :(得分:1)
i = 1
while i < 100 do
final = rand(i+3..i+20)
(a ||= []).push(final)
i +=20
end
p a
一些随机的例子。
[18, 39, 48, 65, 83]
[9, 27, 56, 66, 100]
[10, 29, 46, 68, 86]
[11, 34, 57, 64, 86]
[3, 31, 46, 70, 99]
[16, 36, 43, 75, 92]
答案 2 :(得分:0)
这个随机版本怎么样?
sample_result = []
arr = (1..100).to_a
diff = 15
result_len = 5
1.upto(result_len) {
sample = arr.sample
sample_result << sample
(sample-diff..sample+diff).each do
|i| arr.delete(i)
end
}
p sample_result.sort
答案 3 :(得分:0)
这是解决这个问题的另一种方法。
允许的最小数字是:
a = Array.new(5) { |i| i * 3 + 1 }
#=> [1, 4, 7, 10, 13]
我们可以将这些数字(或这组数字)增加100 - 13 = 87次,直到我们结束:
87.times { a[0..-1] = a[0..-1].map(&:next) }
a #=> [88, 91, 94, 97, 100]
这是允许的最大数字。
我们不是递增所有元素,而是每次都可以选择一个随机元素并递增一个(并且它是正确的邻居):
def spread(size, count, step)
arr = Array.new(count) { |i| i * step + 1 }
(size - arr.last).times do
i = rand(0..arr.size)
arr[i..-1] = arr[i..-1].map(&:next)
end
arr
end
5.times do
p spread(100, 5, 3)
end
输出:
[21, 42, 56, 73, 86]
[6, 21, 45, 61, 81]
[20, 33, 48, 63, 81]
[12, 38, 55, 75, 90]
[11, 29, 50, 71, 86]
[26, 44, 64, 79, 95]
不幸的是,我们必须循环几次才能生成最终值。这不仅速度慢,而且导致分布不均匀:
最好确定总计为87的6个随机偏移并相应地移动元素。为什么6?因为偏移量是我们5个数字之间的距离,即:
n1 n2 n3 n4 n5
|<-o1->|<--o2-->|<-------o3------->|<-o4->|<----o5---->|<----o6---->|
0 max
这个辅助方法返回这样的偏移量:(从here被盗)
def offsets(size, count)
offsets = Array.new(count) { rand(0..size) }.sort
[0, *offsets, size].each_cons(2).map { |a, b| b - a }
end
o = offsets(87, 5) #=> [3, 0, 15, 4, 64, 1]
o.inject(:+) #=> 87
我们可以将偏移量添加到我们的初始数字数组中:
def spread(size, count, step)
arr = Array.new(count) { |i| i * step }
offsets(size - arr.last, count).each_with_index do |offset, index|
arr[index..-1] = arr[index..-1].map { |i| i + offset }
end
arr
end
5.times do
p spread(99, 5, 3)
end
输出:
[1, 14, 48, 60, 94]
[12, 46, 54, 67, 72]
[8, 14, 35, 40, 45]
[27, 30, 51, 81, 94]
[63, 79, 86, 90, 96]
正如预期的那样,这会导致随机分布:
看起来更好。请注意,这些结果基于零。
我们甚至可以删除初始数组并从偏移量计算最终值。从第一个偏移量开始,我们只需要添加以下每个偏移量加上3:
def spread(size, count, step)
offs = offsets(size - (count - 1) * step, count)
(1...offs.size).each { |i| offs[i] += offs[i-1] + step }
offs[0, count]
end