这是我到目前为止有:
myArray.map!{ rand(max) }
但很明显的,有时在列表中的号码是不是唯一的。 我怎样才能让,而无需创建一个更大的列表,从中我那么随便挑n个独特的数字肯定我的列表中只有唯一的数字?
编辑:
我很想看到这个做W / O循环 - 如果可能的话。
这是我到目前为止有:
myArray.map!{ rand(max) }
但很明显的,有时在列表中的号码是不是唯一的。 我怎样才能让,而无需创建一个更大的列表,从中我那么随便挑n个独特的数字肯定我的列表中只有唯一的数字?
编辑:
我很想看到这个做W / O循环 - 如果可能的话。
它使用设置:
require 'set'
def rand_n(n, max)
randoms = Set.new
loop do
randoms << rand(max)
return randoms.to_a if randoms.size >= n
end
end
(0..50).to_a.sort{ rand() - 0.5 }[0..x]
(0..50).to_a
可以与任何阵列来代替。 0是“MINVALUE”,50为“最大值” X是“有多少价值,我想出去”
当然,其不可能被允许X为比最大最小更大:)
在如何工作的扩展
(0..5).to_a ==> [0,1,2,3,4,5]
[0,1,2,3,4,5].sort{ -1 } ==> [0, 1, 2, 4, 3, 5] # constant
[0,1,2,3,4,5].sort{ 1 } ==> [5, 3, 0, 4, 2, 1] # constant
[0,1,2,3,4,5].sort{ rand() - 0.5 } ==> [1, 5, 0, 3, 4, 2 ] # random
[1, 5, 0, 3, 4, 2 ][ 0..2 ] ==> [1, 5, 0 ]
值得一提的是,在当时这个问题最初回答,2008年9月,该Array#shuffle
要么不提供或不已经知道我,因此近似Array#sort
还有的修改建议接二连三这个结果。
所以:
.sort{ rand() - 0.5 }
可以更好的和更短的使用现代Ruby实现表达
.shuffle
另外,
[0..x]
可以更明显地写有Array#take
如下:
.take(x)
因此,生产上的现代红宝石随机数序列的最简单的方法是:
(0..50).to_a.shuffle.take(x)
只给你关于速度的想法,我跑的这四个版本:
他们都很快在小尺度,所以我让他们每个创建百万号码列表。 这里有时间,以秒为:
不,那最后一个是不是一个错字。 所以,如果你在乎速度,这是确定的数字是从0到什么,然后我确切的代码是整数:
a = (0...1000000).sort_by{rand}
红宝石1.9提供,它返回一个元素,或从数组随机选择的元件阵列#样品的方法。 #sample的结果将不包括两次相同的数组元素。
(1..999).to_a.sample 5 # => [389, 30, 326, 946, 746]
当相比于to_a.sort_by
方法中, sample
的方法似乎是显著更快。 在一个简单的场景我比较sort_by
来sample
,并得到下面的结果。
require 'benchmark'
range = 0...1000000
how_many = 5
Benchmark.realtime do
range.to_a.sample(how_many)
end
=> 0.081083
Benchmark.realtime do
(range).sort_by{rand}[0...how_many]
end
=> 2.907445
是的,这是可以做到这一点没有一个循环,并没有保留这些号码已被选定轨道。 这就是所谓的线性反馈移位寄存器: 有没有重复创建随机数序列
如何在这个戏? 独特的随机数,而无需使用设置或哈希。
x = 0
(1..100).map{|iter| x += rand(100)}.shuffle
你可以使用哈希来跟踪到目前为止你已经使用的随机数:
seen = {}
max = 100
(1..10).map { |n|
x = rand(max)
while (seen[x])
x = rand(max)
end
x
}
而不是项目添加到列表/数组,将它们添加到组。
如果有可能的随机数(即1〜100)的有限列表,然后肯特的解决方案是好的。
否则,有没有另做它没有循环的好方法。 问题是你必须做的一环,如果你得到一个副本。 我的解决办法应该是高效和循环不应该比你的数组的大小太大以上(也就是说,如果你想20张不同的随机数,它可能平均需要25次迭代。)虽然迭代的次数变得更糟了更多的数字你需要和较小的最大值是。 下面是修改了我上面的代码显示有多少次迭代都需要给定输入:
require 'set'
def rand_n(n, max)
randoms = Set.new
i = 0
loop do
randoms << rand(max)
break if randoms.size > n
i += 1
end
puts "Took #{i} iterations for #{n} random numbers to a max of #{max}"
return randoms.to_a
end
我可以写这样的代码,如果你想看起来更像Array.map :)
基于以上肯特弗雷德里克的解决方案,这就是我最终使用:
def n_unique_rand(number_to_generate, rand_upper_limit)
return (0..rand_upper_limit - 1).sort_by{rand}[0..number_to_generate - 1]
end
感谢肯特。
用这种方法没有循环
Array.new(size) { rand(max) }
require 'benchmark'
max = 1000000
size = 5
Benchmark.realtime do
Array.new(size) { rand(max) }
end
=> 1.9114e-05
这里是一个解决方案:
假设你希望这些随机数是介于r_min
和r_max
。 对于在列表中的每个元素,生成一个随机数r
使list[i]=list[i-1]+r
。 这将使你的随机数这是单调递增,保证独特性规定
r+list[i-1]
不超过流 r
> 0 对于第一个元素,你可以使用r_min
,而不是list[i-1]
一旦你完成,你可以这样的元素不是那么明显,为了改组列表。
用这种方法唯一的问题是,当你去r_max
,仍然有更多的元素来产生。 在这种情况下,您可以重置r_min
和r_max
你已经计算出两个相邻的元素,简单地重复这个过程。 这有效地运行在那里有没有已经使用的号码的间隔相同的算法。 您可以继续这样做,直到你有填充列表。
至于它是很好预先知道的最大信号值,你可以这样说:
class NoLoopRand
def initialize(max)
@deck = (0..max).to_a
end
def getrnd
return @deck.delete_at(rand(@deck.length - 1))
end
end
你可以得到这样的随机数据:
aRndNum = NoLoopRand.new(10)
puts aRndNum.getrnd
你会获得nil
当所有的值将从甲板exausted。
使用肯特的方法,它是能够产生任意长度保持所有值在有限范围内的数组:
# Generates a random array of length n.
#
# @param n length of the desired array
# @param lower minimum number in the array
# @param upper maximum number in the array
def ary_rand(n, lower, upper)
values_set = (lower..upper).to_a
repetition = n/(upper-lower+1) + 1
(values_set*repetition).sample n
end
另外,可能更有效 ,方法同样从肯特郡的修改另一个答案 :
def ary_rand2(n, lower, upper)
v = (lower..upper).to_a
(0...n).map{ v[rand(v.length)] }
end
puts (ary_rand 5, 0, 9).to_s # [0, 8, 2, 5, 6] expected
puts (ary_rand 5, 0, 9).to_s # [7, 8, 2, 4, 3] different result for same params
puts (ary_rand 5, 0, 1).to_s # [0, 0, 1, 0, 1] repeated values from limited range
puts (ary_rand 5, 9, 0).to_s # [] no such range :)