Search code examples
rubyrandomirbshuffle

Ruby - return an array in random order


What is the easiest way to return an array in random order in Ruby? Anything that is nice and short that can be used in an IRB session like

[1,2,3,4,5].random()
# or 
random_sort([1,2,3,4,5])

Solution

  • If you don't have [].shuffle, [].sort_by{rand} works as pointed out by sepp2k. .sort_by temporarily replaces each element by something for the purpose of sorting, in this case, a random number.

    [].sort{rand-0.5} however, won't properly shuffle. Some languages (e.g. some Javascript implementations) don't properly shuffle arrays if you do a random sort on the array, with sometimes rather public consequences.

    JS Analysis (with graphs!): http://www.robweir.com/blog/2010/02/microsoft-random-browser-ballot.html

    Ruby is no different! It has the same problem. :)

    #sort a bunch of small arrays by rand-0.5
    a=[]
    100000.times{a <<  [0,1,2,3,4].sort{rand-0.5}}
    
    #count how many times each number occurs in each position
    b=[]
    a.each do |x|
        x.each_index do |i|
            b[i] ||=[]
            b[i][x[i]] ||= 0
            b[i][x[i]] += 1
        end
    end
    p b
    

    =>

    [[22336, 18872, 14814, 21645, 22333],
     [17827, 25005, 20418, 18932, 17818],
     [19665, 15726, 29575, 15522, 19512],
     [18075, 18785, 20283, 24931, 17926],
     [22097, 21612, 14910, 18970, 22411]]
    

    Each element should occur in each position about 20000 times. [].sort_by(rand) gives much better results.

    #sort with elements first mapped to random numbers
    a=[]
    100000.times{a <<  [0,1,2,3,4].sort_by{rand}}
    
    #count how many times each number occurs in each position
    ...
    

    =>

    [[19913, 20074, 20148, 19974, 19891],
     [19975, 19918, 20024, 20030, 20053],
     [20028, 20061, 19914, 20088, 19909],
     [20099, 19882, 19871, 19965, 20183],
     [19985, 20065, 20043, 19943, 19964]]
    

    Similarly for [].shuffle (which is probably fastest)

    [[20011, 19881, 20222, 19961, 19925],
     [19966, 20199, 20015, 19880, 19940],
     [20062, 19894, 20065, 19965, 20014],
     [19970, 20064, 19851, 20043, 20072],
     [19991, 19962, 19847, 20151, 20049]]