Say you want to generate a random number between 1 and 1 billion:
rand(1..1_000_000_000)
Will Ruby create an array from that range every time you call this line of code?
Rubocop suggests this approach over rand(1_000_000_000)+1 but it seems there's potential for pain.
Ruby's docs say this:
# When +max+ is a Range, +rand+ returns a random number where
# range.member?(number) == true.
Where +max+ is the argument passed to rand, but it doesn't say how it gets the number argument. I'm also not sure if calling .member? on a range is performant.
Any ideas?
I can use benchmark but still curious about the inner workings here.
No, Ruby will not create an array from that range, unless you explicitly call the
.to_amethod on theRangeobject. In fact,rand()doesn't work on arrays -.sampleis the method to use for returning a random element from an array.The
Rangeclass includesEnumerableso you get Enumerable's iteration methods without having to convert the range into an array. The lower and upper limits for a Range are(-Float::INFINITY..Float::INFINITY), although that will result in aNumerical argument out of domainerror if you pass it intorand.As for
.member?, that method simply calls a C function calledrange_coverthat calls another one calledr_cover_pwhich checks if a value is between two numbers or strings.To test the difference in speed between passing a range to
randand callingsampleon an array, you can perform the following test:As you can see in the first example, passing in a
rangeas a parameter torandis extremely rapid.Contrarily, calling
.to_a.sampleon a range is rather slow. This is due to the array creation process which requires allocating the appropriate data into memory. The.samplemethod should be relatively fast as it simply passes a random and unique index into the array and returns that element.To check out the code for
rangehave a look here.