即日起在codingBlog上分享您的技术经验即可获得积分,积分可兑换现金哦。

如何在Ruby中生成n个唯一随机数的列表?

栈溢出 MrValdez 34℃ 0评论
本文目录
[隐藏]

1.原始问题:How do I generate a list of n unique random numbers in Ruby?

This is what I have so far:

myArray.map!{ rand(max) }

Obviously, however, sometimes the numbers in the list are not unique. How can I make sure my list only contains unique numbers without having to create a bigger list from which I then just pick the n unique numbers?

Edit:
I’d really like to see this done w/o loop – if at all possible.

2.被采纳答案

This uses 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

3.其他高票答案

3.1.第1个答案

(0..50).to_a.sort{ rand() - 0.5 }[0..x] 

(0..50).to_a can be replaced with any array.
0 is “minvalue”, 50 is “max value”
x is “how many values i want out”

of course, its impossible for x to be permitted to be greater than max-min 🙂

In expansion of how this works

(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 ]

3.2.Footnotes:

It is worth mentioning that at the time this question was originally answered, September 2008, that Array#shuffle was either not available or not already known to me, hence the approximation in Array#sort

And there’s a barrage of suggested edits to this as a result.

So:

.sort{ rand() - 0.5 }

Can be better, and shorter expressed on modern ruby implementations using

.shuffle

Additionally,

[0..x]

Can be more obviously written with Array#take as:

.take(x)

Thus, the easiest way to produce a sequence of random numbers on a modern ruby is:

(0..50).to_a.shuffle.take(x)

3.3.第2个答案

Just to give you an idea about speed, I ran four versions of this:

  1. Using Sets, like Ryan’s suggestion.
  2. Using an Array slightly larger than necessary, then doing uniq! at the end.
  3. Using a Hash, like Kyle suggested.
  4. Creating an Array of the required size, then sorting it randomly, like Kent’s suggestion (but without the extraneous “- 0.5”, which does nothing).

They’re all fast at small scales, so I had them each create a list of 1,000,000 numbers. Here are the times, in seconds:

  1. Sets: 628
  2. Array + uniq: 629
  3. Hash: 645
  4. fixed Array + sort: 8

And no, that last one is not a typo. So if you care about speed, and it’s OK for the numbers to be integers from 0 to whatever, then my exact code was:

a = (0...1000000).sort_by{rand}

3.4.第3个答案

Ruby 1.9 offers the Array#sample method which returns an element, or elements randomly selected from an Array. The results of #sample won’t include the same Array element twice.

(1..999).to_a.sample 5 # => [389, 30, 326, 946, 746]

When compared to the to_a.sort_by approach, the sample method appears to be significantly faster. In a simple scenario I compared sort_by to sample, and got the following results.

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

3.5.第4个答案

Yes, it’s possible to do this without a loop and without keeping track of which numbers have been chosen. It’s called a Linear Feedback Shift Register: Create Random Number Sequence with No Repeats

转载请注明:CodingBlog » 如何在Ruby中生成n个唯一随机数的列表?

喜欢 (0)or分享 (0)
发表我的评论
取消评论

*

表情