简体   繁体   中英

How can I shuffle an array/hash in Ruby?

For learning purposes, what is this called? Is the object being created an array or a hash?

stack_of_cards = []

This is how I'm filling it:

stack_of_cards << Card.new("A", "Spades", 1)
stack_of_cards << Card.new("2", "Spades", 2)
stack_of_cards << Card.new("3", "Spades", 3)
...

Here is my Card class:

class Card

  attr_accessor :number, :suit, :value

  def initialize(number, suit, value)
    @number = number
    @suit = suit
    @value = value
  end

  def to_s
    "#{@number} of #{@suit}"
  end
end

I'd like to shuffle the elements in this array/hash (what is this called? :S)

Any suggestions?

stack_of_cards.shuffle

It is an Array, see http://www.ruby-doc.org/core-1.8.7/classes/Array.html for more information.

I've written the functional form, which returns a new Array, and it's the new one that's shuffled. You can instead use:

stack_of_cards.shuffle!

...to shuffle the array in-place.

If you want to shuffle a hash you can use something like this:

class Hash
  def shuffle
    Hash[self.to_a.sample(self.length)]
  end

  def shuffle!
    self.replace(self.shuffle)
  end
end

I've posted this answer since I always find this question if I search for "ruby shuffle hash".

If you wanted to get crazy and write your own in-place shuffle method, you could do something like this.

 def shuffle_me(array)
   (array.size-1).downto(1) do |i|
     j = rand(i+1)
     array[i], array[j] = array[j], array[i]
   end

   array
 end 

For arrays:

array.shuffle
[1, 3, 2].shuffle
#=> [3, 1, 2]

For hashes:

Hash[*hash.to_a.shuffle.flatten]
Hash[*{a: 1, b: 2, c: 3}.to_a.shuffle.flatten(1)]
#=> {:b=>2, :c=>3, :a=>1}
#=> {:c=>3, :a=>1, :b=>2}
#=> {:a=>1, :b=>2, :c=>3}
# Also works for hashes containing arrays
Hash[*{a: [1, 2], b: [2, 3], c: [3, 4]}.to_a.shuffle.flatten(1)]
#=> {:b=>2, :c=>3, :a=>1}
#=> {:c=>[3, 4], :a=>[1, 2], :b=>[2, 3]}

In addition to using the shuffle method , you can use the sort method:

array.sort {|a, b| rand <=> rand }

This may be of use if you are using an older version of Ruby where shuffle is not implemented. As with shuffle! , you can use sort! to work on the existing array.

Old question, but maybe help for someone else. I used it to create a card game, that's what @davissp14 wrote, it's called "Fisher-Yates algorithm"

module FisherYates

  def self.shuffle(numbers)
    n = numbers.length
    while n > 0 
      x = rand(n-=1)
      numbers[x], numbers[n] = numbers[n], numbers[x]
    end
    return numbers
  end

end 

Now you can use it as:

numbers_array = [1,2,3,4,5,6,7,8,9]
asnwer = FisherYates.shuffle(numbers_array)
return answer.inspect

https://dev.to/linuxander/fisher-yates-shuffle-with-ruby-1p7h

If you want to shuffle a hash, but don't want to overload the Hash class, you can use the sort function and then convert it back to a hash with the to_h function (Ruby 2.1+):

a = {"a" => 1, "b" => 2, "c" => 3}
puts a.inspect
a = a.sort {|a, b| rand <=> rand }.to_h
puts a.inspect

For an array:

array.shuffle

For a hash:

hash.sort_by{ rand() }

An alternative hash shuffle is..

hash.to_a.shuffle.to_h

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM