In Ruby 1.8/1.9 both sort
and sort_by
are implemented in C, this is a rough equivalent of how this works:
Say you start with [1,2,3,4]
and call sort_by{rand}
Step 1 (I invented some random numbers):
An array of tuples is created: [[0.12232, 1],[0.53434, 2],[0.333, 3],[0.99, 4]]
In roughly equivalent Ruby code this is: [1,2,3,4].map{|x| [rand, x]}
Step 2
Ruby's quick sort is performed on the array based off the first element: (note the internal implementation is far from trivial and contains a ton of optimisations for already ordered arrays and such)
[[0.12232, 1],[0.333, 3],[0.53434, 2],[0.99, 4]]
In rough ruby this step is: ary.sort{|x,y| x[0] <=> y[0]}
Step 3
Pointers are copied from the new sorted array, to the correct position in the original array.
[1,3,2,4]
In rough ruby this step is: ary.map{|x,y| y}
This technique is sometimes referred to as Schwartzian Transform. Caching means that the expensive operation is not performed more than N times. Meaning, this is a very efficient way of randomizing an array.
Note: array.shuffle!
will be the most efficient built-in way to shuffle an array (in-place) since it uses a modern version of Fisher-Yates
static VALUE
rb_ary_shuffle_bang(VALUE ary)
{
long i = RARRAY_LEN(ary);
rb_ary_modify(ary);
while (i) {
long j = rb_genrand_real()*i;
VALUE tmp = RARRAY_PTR(ary)[--i];
RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j];
RARRAY_PTR(ary)[j] = tmp;
}
return ary;
}