How can I shuffle an array/hash in Ruby? - 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".

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.

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]}

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

Related

Stable #sort taking a block

We find here an implementation of a stable sort_by in Ruby, which works for the general case (i.e. I can supply my own comparision algorithm), and in this thread user tokland describes a very elegant way to do a stable sort_by:
module Enumerable
def stable_sort_by
sort_by.with_index { |x, idx| [yield(x), idx] }
end
end
The idea of using an Enumerator object together with with_index is surprisingly simple! I would like to find a similar elegant solution to create a stable version of the #sort function where it is given a comparison block. It would be used like this:
sorted_people = people.stable_sort do |person|
person.name
end
Here's a solution (but far from elegant):
module Enumerable
def stable_sort
each_with_index.sort { |(x, i), (y, j)|
r = yield(x, y)
r == 0 ? i <=> j : r
}.map(&:first)
end
end
It generates an array of [element, index] pairs and sorts them by passing each two elements to the given block (just like sort does). If the block returns 0, it compares the indices, otherwise, it returns the block's result. Afterwards, the elements are extracted from the generated array.
Example:
arr = [[2, :baz], [1,:foo], [1, :bar]]
arr.sort { |x, y| x[0] <=> y[0] }
#=> [[1, :bar], [1, :foo], [2, :baz]]
arr.stable_sort { |x, y| x[0] <=> y[0] }
#=> [[1, :foo], [1, :bar], [2, :baz]]

How do I create a hash where the keys are values from an array Ruby

I have an array:
arr = [a, ab, abc]
I want to make a hash, using the values of the array as the keys:
newhash = [a[1], ab[1], abc[1]]
I have tried:
arr.each do |r|
newhash[r] == 1
end
to no avail.
How would I about accomplishing this in ruby?
If you are feeling like a one-liner, this will work as well
h = Hash[arr.collect { |v| [v, 1] } ]
collect is invoked once per element in the array, so it returns an array of 2-element arrays of key-value pairs.
Then this is fed to the hash constructor, which turns the array of pairs into a hash
You could also use the #reduce method from Enumerable (which is included into the Array class).
new_hash = arr.reduce({}) { |hsh, elem| hsh[elem] = 1; hsh }
And your new_hash looks like this in Ruby:
{"a": 1, "ab": 1, "abc": 1}
== is comparison. = is assigning. So just modify == into =. It works.
newhash = {}
arr.each do |r|
newhash[r] = 1
end
(I believe a, ab, abc are strings)
To learn more, this might help you. Array to Hash Ruby
You can do it like this:
ary = [[:foo, 1], [:bar, 2]]
Hash[ary] # => {:foo=>1, :bar=>2}
If you want to do it like you tried earlier, you want to initialize hash correctly:
ary = [:foo, :bar]
hash = {}
ary.each do |key|
hash[key] = 1
end # => {:foo=>1, :bar=>2}

How to make an argument of the method, the array and hash,simultaneously

I need send in method argument which is array and hash simultaneously. But don't know, how. Here is example:
def method(here should be this argument)
end
def show(*a)
p a
if a.length.even? == true
p Hash[*a]
else
p "hash conversion not possible"
end
end
show(1,2,3,4)
show(1,2,3)
output:
[1, 2, 3, 4]
{1=>2, 3=>4}
[1, 2, 3]
"hash conversion not possible"
EDIT:
From comment of OP here is the code OP could use:
def add(*arg)
#entries = {}
arg.each_slice(2) do |a| #entries[a.first] = a.last end
p #entries
end
add(1,2,3,4)
Output:
{1=>2, 3=>4}

Ruby - mapping an array to hashmap

I have an array, and a function that returns a value given a value. Ultimately I want to create a hashmap that has the values of the array as key value, and the result of f(key_value) as the value. Is there a clean, simple way, like similar to each/map of Array, of doing this using block?
So something that is equivalent to
hsh = {}
[1,2,3,4].each do |x|
hsh[x] = f(x)
end
but looks more similar to this, in that it's simple and one line?
results = array.map { | x | f(x) }
Note that since Ruby 2.1.0 you can also use Array#to_h, like this:
[1,2,3,4].map{ |x| [x, f(x)] }.to_h
Ruby 2.6.0 enables passing a block to the to_h-method. This enables an even shorter syntax for creating a hash from an array:
[1, 2, 3, 4].to_h { |x| [x, f(x)] }
You could also define the function as the hash's default value:
hash = Hash.new {|hash, key| hash[key] = f(key) }
Then when you lookup a value, the hash will calculate and store it on the fly.
hash[10]
hash.inspect #=> { 10 => whatever_the_result_is }
You need each_with_object.
def f x
x * 2
end
t = [1, 2, 3, 4].each_with_object({}) do |x, memo|
memo[x] = f(x)
end
t # => {1=>2, 2=>4, 3=>6, 4=>8}
Another one:
t2 = [1, 2, 3, 4].map{|x| [x, f(x)]}
Hash[t2] # => {1=>2, 2=>4, 3=>6, 4=>8}
Check out the Hash::[] method.
Hash[ [1,2,3,4].collect { |x| [x, f(x)] } ]
Using Facets' mash (method to convert enumerable to hashes):
[1, 2, 3, 4].mash { |x| [x, f(x)] }
From Ruby 2.1:
[1, 2, 3, 4].map { |x| [x, f(x)] }.to_h
Also, Rails method index_with would be helpful:
a = ['a', 'bsdf', 'wqqwc']
a.index_with(&:size)
=> {"a"=>1, "bsdf"=>4, "wqqwc"=>5}
You're looking for reduce()|inject() method:
elem = [1,2,3,4]
h = elem.reduce({}) do |res, x|
res[x] = x**2
res
end
puts h
The argument passed to reduce({}) is the initial value of an intermediate object that is passed to the block as res variable. In each iteration we're adding new pair key: value to the res Hash and returing the Hash to be used in next iteration.
The method above precomputes a very practical hash of squared values:
{1=>1, 2=>4, 3=>9, 4=>16}

Why are the values empty in a Hash after inserting an array?

I have an array of numbers where I want the individual numbers to be the key and the array itself to be the value. Doing this poses no problems
keys.each do |i|
myHash[i] = keys
end
But now I want the values to be the array minus the first value for every subsequent iteration so I did this
keys = Array.new
numbers.each do |i|
keys.push(i)
end
keys.each do |i|
# puts i
# puts numbers.inspect
myHash[i] = numbers
numbers.shift
end
And it gives me empty arrays as the values in my hash for all the keys. Why is that? Ultimately, I want my hash to look like this given an array of [1, 2, 3, 4]
{1=>[1, 2, 3, 4], 2=>[2, 3, 4], 3=>[3, 4], 4=>[4]}
Thank you!
You are not doing a deep copy of the array.
Try :
keys.each do |i|
# puts i
# puts numbers.inspect
myHash[i] = numbers.clone
numbers.shift
end

Resources