How can I grab certain values in a hash in Ruby? - ruby-on-rails

I have a hash
hash = { 1=> { 0=> 'apple', 1=> 'tree'... ....}, 2=> {.....}}
I want to grab the 0 for all hashes within the hash. I know there is a transpose for array, but there any way to do this with a hash easily?

Something like this should work:
hash.values.collect{|v| v[0]}
Example:
irb(main):001:0> hash = { 1 => { 0 => 'apple', 1 => 'tree' },
2 => { 0 => 'foo', 1 => 'bar' }}
=> {1=>{0=>"apple", 1=>"tree"}, 2=>{0=>"foo", 1=>"bar"}}
irb(main):002:0> hash.values.collect{|value| value[0]}
=> ["apple", "foo"]

Related

Sort items in a nested hash by their key

I have a nested hash with unsorted keys:
given = {
"lorem" => {
:AA => "foo",
:GR => "foo",
:BB => "foo"
},
"ipsum" => {
:ZZ => "foo",
:GR => "foo",
}
}
What I'm trying to accomplish is a hash with sorted keys:
goal = {
"ipsum" => {
:GR => "foo",
:ZZ => "foo"
},
"lorem" => {
:AA => "foo",
:BB => "foo",
:GR => "foo"
}
}
I have experimented with .each method and sort_by
given.each { |topic| topic[:key].sort_by { |k, v| k } }
But I'm getting an error message: TypeError: no implicit conversion of Symbol into Integer
Any help is greatly appreciated!
PS: I noticed with gem pry the output is already sorted. But in IRB it's not.
You can use group_by, and transform_values to transform the values inside each hash, also using sort_by plus to_h:
given.transform_values { |value| value.sort.to_h }.sort.to_h
# {"ipsum"=>{:GR=>"foo", :ZZ=>"foo"}, "lorem"=>{:AA=>"foo", :BB=>"foo", :GR=>"foo"}}
You're getting an error because when iterating over a hash, you have to local variables within the block scope to use, the key and its value, you're assigning only one (topic) and trying to get its key, which would be trying to access a key in:
["lorem", {:AA=>"foo", :GR=>"foo", :BB=>"foo"}]
Which isn't possible as is an array. You can update your code to:
given.each do |topic, value|
...
end
But anyway you'll need a way to store the changes or updated and sorted version of that topic values.
given_hash = {"lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}, "ipsum"=>{:ZZ=>"foo", :GR=>"foo"}}
Get keys
given_hash.keys
=> ["lorem", "ipsum"]
New sorted hash
new_hash = {}
given_hash.keys.sort.each do |sorted_key|
new_hash[sorted_key] = given[sorted_key]
end
=> {"ipsum"=>{:ZZ=>"foo", :GR=>"foo"}, "lorem"=>{:AA=>"foo", :GR=>"foo", :BB=>"foo"}}
There can be a better way to do this.

Grabbing a specific hash in an array that meets a specific criteria

I have a huge array full of a bunch of hashes. What I need to do is single out one index hash from the array that meets a specific criteria. (doing this due to an rspec test, but having trouble singling out one of them)
My array is like this
[
{
"name" => "jon doe",
"team" => "team2",
"price" => 2000,
"eligibility_settings" => {}
},
{
"name" => "jonny doe",
"team" => "team1",
"value" => 2000,
"eligibility_settings" => {
"player_gender" => male,
"player_max_age" => 26,
"player_min_age" => 23,
"established_union_only" => true
}
},
{
"name" => "jonni doe",
"team" => "team3",
"price" => 2000,
"eligibility_settings" => {}
},
]
I need to single out the second one, based on its eligibility settings. I just took three of them from my array, have lots more, so simple active record methods like (hash.second) won't work in this instance.
I've tried things like
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
However when I try this, I get a nil response. (which is odd)
I've also looked into using the ruby detect method, which hasn't gotten me anywhere either
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Would anybody have any idea what to do with this one?
Notes
players.team.map(&:hash).find{ |x| x[ 'eligibility_settings?' ] == true}
Players.team.map(&:hash).['hash.seligibiltiy_settings'].detect { true }
Is is players or Players ?
Why is it plural?
If you can call map on team, it probably should be plural
Why do you convert to a hash?
eligibility_settings? isn't a key in your hash. eligibility_settings is
eligibility_settings can be a hash, but it cannot be true
If you want to check if it isn't empty, use !h['eligibility_settings'].empty?
Possible solution
You could use :
data = [
{
'name' => 'jon doe',
'team' => 'team2',
'price' => 2000,
'eligibility_settings' => {}
},
{
'name' => 'jonny doe',
'team' => 'team1',
'value' => 2000,
'eligibility_settings' => {
'player_gender' => 'male',
'player_max_age' => 26,
'player_min_age' => 23,
'established_union_only' => true
}
},
{
'name' => 'jonni doe',
'team' => 'team3',
'price' => 2000,
'eligibility_settings' => {}
}
]
p data.find { |h| !h['eligibility_settings'].empty? }
# {"name"=>"jonny doe", "team"=>"team1", "value"=>2000, "eligibility_settings"=>{"player_gender"=>"male", "player_max_age"=>26, "player_min_age"=>23, "established_union_only"=>true}}
If h['eligibility_settings'] can be nil, you can use :
data.find { |h| !h['eligibility_settings'].blank? }
or
data.find { |h| h['eligibility_settings'].present? }

Accepting either a hash or an array of hashes as arguments to a Ruby method

I have the method:
def self.store(params)
params.each { }
end
It works perfectly, if I pass an Array of Hashes:
params = [ { key: 'value' }, { key: 'value' } ]
However, I might want to pass only a single Hash, instead of an Array of Hashes:
params = { key: 'value' }
What would be the cleanest Ruby way to convert a Hash into an Array of Hashes?
The Array() method a kind of ensures, that an array is always returned, but when the Hash is passed, it is converted into an Array itself.
Array({ key: 'value' }) => [[:key, 'value']]
What I need:
{ key: 'value' } => [ { key: 'value' } ]
Is there any nice way to implement this, or do I have to do a manual type checking with is_a?(Array) ?
For me, the best solution is to change the method to:
def self.store(*hashes)
params = hashes.flatten
puts params.inspect
end
If you pass a single hash, it will be an array
If you pass an array of hashes, it remains the same
If you pases N hashes, it compacts all parameters into a one dimensional array.
You can pass whatever you want.
self.store({:key => 'value'}) # => [{:key => 'value'}]
self.store({:key => 'value'}, {:foo => 'bar'}) # => [{:key => 'value'}, {:foo => 'bar'}]
self.store([{:key => 'value'}, {:foo => 'bar'}]) # => [{:key => 'value'}, {:foo => 'bar'}]
Try this
def self.store(params)
params = [params].flatten
...
end
I would do it like this:
def self.store(params)
(params.is_a?(Array) ? params : [params]).each {|single_hash| }
end

How to retrieve values related to a hash key present in a Array of Hashes

I am using Ruby on Rails 3.2.2 and I would like to retrieve values related to a hash key present in a Array of Hashes. That is, I have the following Array of Hashes:
[
{
:key1 => value_a_1,
:key2 => value_a_2
},
{
:key1 => value_b_1,
:key2 => value_b_2
},
{
:key1 => value_c_1,
:key2 => value_c_2
}
]
I would like to "retrieve" / "build" the following:
[ value_a_1, value_b_1, value_c_1 ]
How can I make that the proper way?
If a is the array:
a.map { |i| i[:key1] }

Sort rails hash based on array of items

I have an array like this:
['one','three','two','four']
I have a array of hash like this:
[{'three' => {..some data here..} }, {'two' => {..some data here..} }, {:total => some_total }] # etc...
I want to sort the array of hashes by the first array. I know I can do:
array_of_hashes.sort_by{|k,v| k.to_s} to sort them and it will sort by the key
( and the .to_s to convert :total to a string )
How can I make this happen?
Edit:
I was incorrect about how this is setup, it is actually like this:
{'one' => {:total => 1, :some_other_value => 5}, 'two' => {:total => 2, :some_other_value => 3} }
If I need to put this in a new question, just let me know and I will do that.
Thank you
similar to ctcherry answer, but using sort_by.
sort_arr = ['one','three','two','four']
hash_arr = [{'three' => {..some data here..} }, {'two' => {..some data here..} }]
hash_arr.sort_by { |h| sort_arr.index(h.keys.first) }
The index method of Array is your friend in this case:
sort_list = ['one','three','two','four']
data_list = [{'three' => { :test => 3 } }, {'two' => { :test => 2 } }, {'one' => { :test => 1 } }, {'four' => { :test => 4 } }]
puts data_list.sort { |a,b|
sort_list.index(a.keys.first) <=> sort_list.index(b.keys.first)
}.inspect
Resulting in, the same order as the source array:
[{"one"=>{:test=>1}}, {"three"=>{:test=>3}}, {"two"=>{:test=>2}}, {"four"=>{:test=>4}}]

Resources