这是我目前的进展:
myArray.map!{ rand(max) }
显然,有时列表中的数字不是唯一的。 如何确保我的列表只包含唯一的数字,而无需创建一个更大的列表,然后从中选择n个唯一的数字?
编辑:
如果可能的话,我真的想看到这样做没有循环。
(0..50).to_a.sort{ rand() - 0.5 }[0..x]
(minvalue..max value).to_a
可以替换为任何数组。
0 为 "minvalue",50 为 "max value",
x 为 "我想要的值的数量"。
当然,x 不可能被允许大于 max-min :)
关于它是如何工作的扩展说明:
(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)
因此,要在现代Ruby上生成一系列随机数的最简单方法是:
Thus, the easiest way to produce a sequence of random numbers on a modern ruby is:(0..50).to_a.shuffle.take(x)
.shuffle
的添加。 - Kent Fredric这里使用了Set:
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
randoms
就不如 rand(max)
随机,因为你只是丢弃了“不喜欢”的数字。 - AllenRuby 1.9提供了Array#sample方法,该方法会从数组中随机选择一个或多个元素。使用#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
只是为了让您了解速度,我运行了以下四个版本:
它们在小规模下都很快,因此我让它们每个创建一个由1,000,000个数字组成的列表。以下是以秒为单位的时间:
不,最后一个不是笔误。因此,如果您关心速度,并且可以接受数字是从0到任意值的整数,则我的精确代码为:
a = (0...1000000).sort_by{rand}
(0..10).to_a.sort { Random.rand() }
在 http://tryruby.org/levels/1/challenges/0 上让我输入与输出相同。所以你确实需要那个-0.5或者随机本身是什么都没做。 - Kent Fredric[*1..99].sample(4) #=> [64, 99, 29, 49]
Array#sample
文档,SecureRandom
(它使用计算机噪声而不是伪随机数):require 'securerandom'
[*1..99].sample(4, random: SecureRandom) #=> [2, 75, 95, 37]
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 :)