Outputting the keys of the max value of a hash within Arrays in Ruby using methods - ruby

data = [
"Company one" => {
"number_1" => 46,
"number_2" => 3055,
"country" => "USA"
},
"Company two" => {
"number_1" => 32,
"number_2" => 6610,
"country" => "USA"
},
"Company three" => {
"number_1" => 40,
"number_2" => 9128,
"country" => "USA"
}
]
So I have this array in which I'm trying to get which of the company has the biggest number in 'number_2'. The largest would be Company three with 9128.
So I have this code that puts the largest number which would be 9128
def number(data)
collected_array=[]
data.each do |company_hash|
collected_array = company_hash.map do |k,v|
v["number_2"]
end
end
puts collected_array.max
end
number(data)
But I'm trying to puts the company name with the largest number which would be "Company three". I've tried .keys and other ways but it gives me error.
I've tried this way:
def number(data)
collected_array=[]
data.each do |company_hash|
collected_array = company_hash.map do |k,v|
v["number_2"]
k
end
end
puts collected_array.max
end
number(data)
but it gives me "Company two" rather than "Company three" which would be the company with the highest number

As stated by #Cary, it can be simplified accessing the first element on data, and there using max_by, on the hash local variable available within the block checking the number_2 key value.
As the result is an Array containing two elements, the first one is the company name, the second and last one, the hash containing its data:
data = [
"Company one" => {
"number_1" => 46,
"number_2" => 3055,
"country" => "USA"
},
"Company two" => {
"number_1" => 32,
"number_2" => 6610,
"country" => "USA"
},
"Company three" => {
"number_1" => 40,
"number_2" => 9128,
"country" => "USA"
}
]
max_company = data.first.max_by { |_, h| h['number_2'] }
p max_company.first # "Company three"
p max_company.last['number_2'] # 9128

Related

Mapping one hash value to other hash ruby

I have a hash which gives me the data in following manner:
details = [{"severity_longevity" => "Medium", "operating_leverage" => "High",
"financial_leverage"=> "Low", "revenue_growth"=> "Low"}]
I have one hash which gives me the score that I am supposed to assign.
score = [{"Low"=> 5},{"Medium"=> 10}, {"High"=> 15}]
How can I change the "Medium" "Low" and "High" in details hash with their number scores from
score hash ?
For Hashes you can use transform_values method
details = {
"severity_longevity" => "Medium",
"operating_leverage" => "High",
"financial_leverage"=> "Low",
"revenue_growth"=> "Low"
}
score = {"Low" => 5, "Medium" => 10, "High" => 15}
updated = details.transform_values { |v| score[v] }
# => { "severity_longevity" => 10, ... }

In Ruby, what's the advantage of #each_pair over #each when iterating through a hash?

Let's say I want to access the values of a hash like this:
munsters = {
"Herman" => { "age" => 32, "gender" => "male" },
"Lily" => { "age" => 30, "gender" => "female" },
"Grandpa" => { "age" => 402, "gender" => "male" },
"Eddie" => { "age" => 10, "gender" => "male" },
"Marilyn" => { "age" => 23, "gender" => "female"}
}
I could use #each with two parameters:
munsters.each do |key, value|
puts "#{name} is a #{value["age"]}-year-old #{value["gender"]}."
end
Or I could use #each_pair with two parameters:
munsters.each_pair do |key, value|
puts "#{name} is a #{value["age"]}-year-old #{value["gender"]}."
end
Perhaps the difference between the two is not borne out in this simple example, but can someone help me to understand the advantage of using #each_pair over #each ?
Because Hash is an Enumerable, it has to have an each method. each_pair may be a clearer name, since it strongly suggests that two-element arrays containing key-value pairs are passed to the block.
They are aliases for each other: they share the same source code.

ruby sort hash based on another hash

I have the following two hashes:
db = {"1" => "first_name", "2" => "last_name", "5" => "status", "10" => "city" }
csv = {"1" => "first_name", "2" => "last_name", "5" => "status", "7" => "address", "10" => "city" }
I want to order csv based on db, and if there are any keys in csv not in db, then I want to move them to the end of csv, so in the above example the result would look like this:
{"1" => "first_name", "2" => "last_name", "5" => "status", "10" => "city", "7" => "address" }
Since the key "7" wasn't in db hash, we just moved it to the end of the csv hash.
This is what I tried:
db = {"1" => "first_name", "2" => "last_name", "5" => "status", "10" => "city" }
csv = {"1" => "first_name", "2" => "last_name", "5" => "status", "7" => "address", "10" => "city" }
rejects = csv.reject {|k| db.include? k }
result = csv.keep_if {|k,_| db.include? k }
result.merge!(rejects)
result
=> {"1"=>"first_name", "2"=>"last_name", "5"=>"status", "10"=>"city", "7"=>"address"}
It seems to work. But is it guaranteed to work? Will the merger always put the second hash at the end, or is there a possibility that the merger could mix the hashes together without consideration of order?
You could do the following:
db_keys = db.keys
#=> ["1", "2", "5", "10"]
keys = db_keys + (csv.keys-db_keys)
#=> ["1", "2", "5", "10", "7"]
Hash[keys.zip(csv.values_at(*keys))]
#=> { "1"=>"first_name", "2"=>"last_name", "5"=>"status",
# "10"=>"city", "7"=>"address"}

ruby one-liner from two hashes

a = {"rows" => [{"id" => "231-z", "name" => 'jon', "age"=> 27, "state" => 'AL'},
{"id" => "4121-x", "name" => 'ton', "age"=> 37, "state" => 'VA'}
]
}
b = {"rows" => [{"key" => ["xyz","4121-x"], "value" =>{"sum" => 12312, "realage" => 29}},
{"key" => ["xyz","231-z"], "value" =>{"sum" => 1212, "realage" => 33}}
]
}
In hash a, age is incorrect
In hash b, realage is correct. Also in hash b id is the second value in the first array that maps to id of hash a . Those are 4121-x, 231-z correspond to hash a
I want to correct the age in hash a and swap it with the realage of hash b
I can do it in multiple steps, but is it possible to do it in one liner or very short? So finally correct hash a should look like
a = {"rows" => [{"id" => "231-z", "name" => 'jon', "age"=> 33, "state" => 'AL'},
{"id" => "4121-x", "name" => 'ton', "age"=> 29, "state" => 'VA'}
]
}
does this look reasonable?
a['rows'].each_with_index do |ah, i|
(bh = b['rows'].select {|h| h['key'].last == ah['id'] }.first) &&
a['rows'][i] = ah.update('age' => bh['value']['realage'])
end
p a
{
"rows" => [
[0] {
"id" => "231-z",
"name" => "jon",
"age" => 33,
"state" => "AL"
},
[1] {
"id" => "4121-x",
"name" => "ton",
"age" => 29,
"state" => "VA"
}
]
}
Please note it will update a only if corresponding id found in b.
Also, the rows order does not matter, nor matter the rows number, it is only important b to have a row with same id as processed row in a
Here is a Working Demo

ruby language - merge an array into another by finding same element

A = [
{ :id => 1, :name => 'good', :link => nil },
{ :id => 2, :name => 'bad', :link => nil }
]
B = [
{ :id => 3, :name => 'good' },
{ :id => 4, :name => 'good' },
{ :id => 5, :name => 'bad' }
]
I need to merge array B into A so that :link in array A includes the entry in array B if :name is the same value in each array.
For example, after processing array A should be:
A = [
{ :id => 1, :name => 'good', :link => [{ :id => 3, :name => 'good' }, { :id => 4, :name => 'good' }] },
{ :id => 2, :name => 'bad', :link => [{ :id => 5, :name => 'bad' }] }
]
thanks.
The short version;
a.each { | item | item[:link] = b.find_all { | x | x[:name] == item[:name] } }
Demo here.
In ruby the constants begin with an uppercase letter, so you should use lowercase letter:
A => a, B => b
a.each do |ha|
b.each do |hb|
if ha[:name] == hb[:name]
ha[:link] |= []
ha[:link] << hb
end
end
end
Functional approach:
B_grouped = B.group_by { |h| h[:name] }
A2 = A.map { |h| h.merge(:link => B_grouped[h[:name]]) }
#=> [{:link=>[{:name=>"good", :id=>3}, {:name=>"good", :id=>4}], :name=>"good", :id=>1},
# {:link=>[{:name=>"bad", :id=>5}], :name=>"bad", :id=>2}]

Resources