Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby recursive shuffle with rand

Tags:

ruby

I am quite new to Ruby and programming in general, and I am currently trying to study with Chris Pine's book. In chapter 10 there is a task that requires you to return a shuffled version of an array.

I tried the following code for the shuffle method itself, and it worked:

def shuffle array
  recursive_shuffle array, []   
end

def recursive_shuffle unshuffled, shuffled
  if unshuffled.length == 1
    shuffled.push unshuffled[0]
    shuffled.pop                      
    return shuffled
  end

  rand_index = rand(unshuffled.length - 1)
  shuffled.push unshuffled[rand_index]
  unshuffled.delete_at(rand_index)
  recursive_shuffle(unshuffled, shuffled)
end

puts(shuffle(array))

I'm wondering about two things.

First I tried doing it without shuffled.pop and with rand_index = rand(unshuffled.length) instead of length - 1.

However, in the answer the element before the last one was always blank, otherwise it was shuffled and no elements were missing. Then I thought the problem should be in the rand and added the - 1.

At this point the array was, again, shuffled properly, but this time there was always one blank last element of the shuffled array. That's why I added shuffled.pop.

It works fine like this, but I don't understand why it adds a blank element in the first two instances.

Also, if I have an array of 2 elements, its length should be 2 and rand_index should be rand(1), but isn't rand(1) supposed to always be 0? The aforementioned code nevertheless shuffles properly arrays with 2 elements.

I looked at various other topics on Ruby, shuffle, and rand, and couldn't find a similar problem.

like image 793
Nikolay D Avatar asked Dec 08 '25 04:12

Nikolay D


1 Answers

If your goal to get the array shuffled you should use the builtin shuffle method, it's both correct and faster than anything you'll write.

If your goal is to implement your own version, this is not well-suited to recursion and you should implement a Fisher-Yates shuffle to avoid bias:

def fy_shuffle(arr)
  a_copy = arr.dup  # don't mutate original array!
  a_copy.each_index do |i|
    j = i + rand(a_copy.length - i)
    a_copy[i], a_copy[j] = a_copy[j], a_copy[i] if i != j
  end
end

If your goal is to learn about recursion, dinjas' answer fixes the problems in your original implementation and works as long as the arrays aren't large enough to blow out the stack.

like image 128
pjs Avatar answered Dec 10 '25 17:12

pjs



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!