208

To generate a random number between 3 and 10, for example, I use: rand(8) + 3

Is there a nicer way to do this (something like rand(3, 10)) ?

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746

8 Answers8

353

UPDATE: Ruby 1.9.3 Kernel#rand also accepts ranges

rand(a..b)

http://www.rubyinside.com/ruby-1-9-3-introduction-and-changes-5428.html

Converting to array may be too expensive, and it's unnecessary.


(a..b).to_a.sample

Or

[*a..b].sample

Array#sample

Standard in Ruby 1.8.7+.
Note: was named #choice in 1.8.7 and renamed in later versions.

But anyway, generating array need resources, and solution you already wrote is the best, you can do.

mgarciaisaia
  • 14,521
  • 8
  • 57
  • 81
Nakilon
  • 34,866
  • 14
  • 107
  • 142
  • Thanks! I think I'll stay with the old and the good method :) – Misha Moroshko Dec 09 '10 at 07:12
  • 34
    This is a really bad idea, especially if your a and b are of unknown sizes. Try (100000000000000000..100000000000000).to_a.sample and see what I mean : ) – pixelearth Sep 16 '11 at 22:06
  • 4
    @pixelearth, if you have better idea, which accords the question, you are welcome to post. – Nakilon Sep 17 '11 at 01:54
  • `rand(a..b)` doesn't work, it splits: `TypeError: can't convert Range into Integer`. It's not even supported in [Ruby 2.0](http://ruby-doc.org/core-2.0/Kernel.html#method-i-rand) – fguillen Mar 09 '13 at 16:00
  • 2
    @fguillen It works for me in 1.9.3, I don't know why it's not working for you. – Michael Dorst Dec 18 '13 at 18:35
  • @anthropomorphic it is working for me in `ruby 2.0.0-p247` so I retract. – fguillen Dec 18 '13 at 20:07
  • @so_mv this doesn't happen on MRI. (2.0.0p594). `1000000.times{|i| a = rand(1000..9999); puts a if a < 1000}` does not puts a single number – Pelle Nov 22 '14 at 00:12
  • 1000.times{|i| puts rand(1000-9999)} is wrong. Notice the minus(-) between 1000-9999. It should be 1000..9999. I will remove my comment – so_mv Nov 25 '14 at 08:10
88
Random.new.rand(a..b) 

Where a is your lowest value and b is your highest value.

Simon Perepelitsa
  • 20,350
  • 8
  • 55
  • 74
user1782571
  • 889
  • 6
  • 2
  • 4
    The important difference to note is that if you just call `rand()` you are calling `Kernel#rand`, which only supports a `max` argument. If you want to pass a range, you have to use `Random#rand`, meaning you have to implement this way. +1 – grumpit Jan 17 '13 at 03:06
  • 2
    should add that the above applies to 1.9.2 – grumpit Jan 17 '13 at 03:20
  • does it include a and b ? – Abhradip Oct 24 '16 at 07:39
13

You can use range operators. Do note the difference between the two forms:

3..10  # includes 10
3...10 # doesn't include 10
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Yaniv Preiss
  • 239
  • 2
  • 7
  • This should probably be a comment instead of an answer, but it's also a very important distinction so I gave it an upvote anyway. :) – Joshua Pinter Jan 28 '23 at 20:03
12
rand(3..10)

Kernel#rand

When max is a Range, rand returns a random number where range.member?(number) == true.

Dorian
  • 22,759
  • 8
  • 120
  • 116
5
def random_int(min, max)
    rand(max - min) + min
end
Chaseph
  • 1,893
  • 3
  • 16
  • 20
3

See this answer: there is in Ruby 1.9.2, but not in earlier versions. Personally I think rand(8) + 3 is fine, but if you're interested check out the Random class described in the link.

Community
  • 1
  • 1
bnaul
  • 17,288
  • 4
  • 32
  • 30
3

For 10 and 10**24

rand(10**24-10)+10
Sayan Malakshinov
  • 8,492
  • 1
  • 19
  • 27
3

And here is a quick benchmark for both #sample and #rand:

irb(main):014:0* Benchmark.bm do |x|
irb(main):015:1*   x.report('sample') { 1_000_000.times { (1..100).to_a.sample } }
irb(main):016:1>   x.report('rand') { 1_000_000.times { rand(1..100) } }
irb(main):017:1> end
       user     system      total        real
sample  3.870000   0.020000   3.890000 (  3.888147)
rand  0.150000   0.000000   0.150000 (  0.153557)

So, doing rand(a..b) is the right thing

Vadym Tyemirov
  • 8,288
  • 4
  • 42
  • 38