如果我有一个从 0 到 70 的数字范围,我想选择五个随机数,并且随机数的总和高于 140 并低于 220。我想这样做直到五个随机数的总和在范围 140..220,然后显示这五个随机数。*
这是我到目前为止所做的:
5.times {r=rand (0..70); puts "#{r}"}
或者:
5.times {puts "#{[*0...70].sample}"}
如果我有一个从 0 到 70 的数字范围,我想选择五个随机数,并且随机数的总和高于 140 并低于 220。我想这样做直到五个随机数的总和在范围 140..220,然后显示这五个随机数。*
这是我到目前为止所做的:
5.times {r=rand (0..70); puts "#{r}"}
或者:
5.times {puts "#{[*0...70].sample}"}
如果您需要实际数字,而不是总和,请使用这一行:
nums = [*0..70].sample(5) until (140..220) === (nums || []).inject(:+)
如果数字可以重复,请改用:
nums = 5.times.collect {rand(0..70)} until (140..220) === (nums || []).inject(:+)
第二个的多行版本,没有统计错误(hat tip samuil):
digits = []
valid = 140..220
until valid === digits.inject(:+)
digits = []
5.times { digits << rand(0..70) }
end
不是很简短的答案,但似乎很清楚,而且是红宝石风格的。
e = Enumerator.new do |y|
loop do
y << 5.times.map { rand(0..70) }
end
end
e.find { |ary| (140..220).include? ary.inject(&:+) }
首先,我们定义枚举器,它返回成批的数字,从 0..70 范围内随机化。稍后,使用#find
我们正在寻找第一个条目的方法,它将满足 (140..220) 范围内的总和条件。
在纯红宝石中
sum = [*0..70].sample(5).inject(&:+) until (140..220) === sum
如果您使用 ActiveSupport,那么您可以使用#sum
而不是inject(&:+)
.
只是为了好玩,这是我能想到的最具声明性的代码:
repeat { (0..70).sample(5) }.detect { |xs| xs.reduce(:+).in?(140...220) }
不存在的抽象的实现留给读者练习:-)
boundary = 140..220
numbers = *0..70
begin
numbers.sample( 5 ).reduce( :+ ).tap do |sum|
fail unless boundary === sum
end
rescue
retry
end
在讨论之后,我想举一个我最近提倡catch
的throw
例子,但这似乎不是一个合适的机会。所以让我用另一种方式来做这件事,没有例外:
class Object
def ergo; yield self end
end
numbers.ergo do |ary|
rslt = ary.sample( 5 ).reduce( :+ )
boundary === rslt ? rslt : redo
end