How to find the key of the largest value hash? - ruby

I have the following hash {"CA"=>2, "MI"=>1, "NY"=>1}
How can I return the maximum key value pair using ruby? I would like it to return "CA"

This will return max hash key-value pair depending on the value of hash elements:
def largest_hash_key(hash)
hash.max_by{|k,v| v}
end

I found this way , return the key of the first max value
hash.key(hash.values.max)

Another way could be as follows:
hash.each { |k, v| puts k if v == hash.values.max }
This runs through each key-value pair and returns (or in this case puts's) the key(s) where the value is equal to the max of all values. This should return more than one key if there's a tie.

If you want to retrieve more than one key value pair based on order(second largest, smallest etc.), a more efficient way will be to sort the hash once and then get the desired results.
def descend_sort(hash)
hash = hash.sort_by {|k,v| v}.reverse
end
Key of largest value
puts *hash[0][0]
Get max and min
puts *hash[0], *hash[hash.length-1]
2nd largest key value pair
Hash[*hash[1]]
To convert the hash array back into a hash
hash.to_h

You can use the select method if you want the key value pair returned:
hash.select {|k,v| v == hash.values.max }

I did this today on a similar problem and ended up with this:
hash = { "CA"=>2, "MI"=>1, "NY"=>1 }
hash.invert.max&.last
=> "CA"
For Ruby less than 2.3 you can replace &.last with .try(:last)
Either one is just a safeguard for if your source hash is empty: {}

This will return the last key of the hash sorted by size; however, there might be two keys with the same value.
def largest_hash_key(hash)
key = hash.sort{|a,b| a[1] <=> b[1]}.last
puts key
end
hash = { "n" => 100, "m" => 100, "y" => 300, "d" => 200, "a" => 0 }
largest_hash_key(hash)

Related

takes in a dictionary key and return an array filled with the appropriate values of the keys

Given the hash
person = {
"cats"=> 2,
"dogs"=> 1
}
I wish to construct the array
["cats", "cats", "dogs"]
"cats" appears twice because person["cats"] #=> 2. For the same reason "dogs" appears once. If the hash had a third key-value pair "pigs"=>3, I would want to return the array
["cats", "cats", "dogs", "pigs", "pigs", "pigs"]
I tried the following code.
arr = person.to_a
i = 0
new_arr = []
while i < arr.length
el = arr[i][0]
final = [new_arr << el]
print final.flatten
i += 1
end
This displays
["cats"]["cats", "dogs"] => nil
but does not seem to return a value.
new_arr
#=> ["cats", "dogs"]
As you see, I am not getting the answer I wanted and do not understand why print displays what I show above.
I would like to know what is wrong with my code and what would be a better way of doing this.
flat_map method will flatten multiple arrays into one
Array operator * creates array with multiple values
result = person.flat_map {|key, value| [key] * value}
# => ["cats", "cats", "dogs"]
Ruby has a lot of nice methods to work with collections. I believe it is better to use them instead of while loop.
You can iterate through the hash using inject
method. The first parameter in the block is the resulting array, that accumulates the result of each iteration, the second is a key/value pair.
person.inject([]) do |array, (key, value)|
array + Array.new(value, key)
end
Or it can be rewritten as a one line.
person.inject([]) { |array, (key, value)| array + Array.new(value, key) }

Ruby, How can I compare two pair of items in array of hashes

I have a array of hashes like :
arry = {hash1, hash2, hash3,hash4 ....hash_N}
for each hash,
hash1 ={ "deviceId"=>"868403021230682", "osVersion"=>"6.0", "deviceOS"=>"Android",
"appVersion"=>"1.7.2", "action"=>"Enter"}
hash2 = { "deviceId"=>"868403021230682", "osVersion"=>"6.0", "deviceOS"=>"Android",
"appVersion"=>"1.7.2", "action"=>"Leave"}
because it is possible that for each hash "action"=>"Enter" or "Leave" will not always appear as a pair , for example, action for hash3, hash4,hash5 could be all "Enter" . My idea is only consider two hashes who can make a pair like hash1 and hash2, remove other from array or put them into other array.
so the new array should just contain [hash1, hash2, hash7,hash8] , lets say hash7 and 8 are also a pair.
should I use each_with_index? my code is like this:
def get_result(doc)
result = []
doc.each_slice(2).map { |pair|
pair.each_with_index { |element, index|
if ( pair[index].has_value?([:action] => "enter") &&pair[index+1].has_value?([:action] => "Leave")
result.push(pair)
end
}
}
end
but the if statement is not working right , kind of confused about how to use each_with_index hope someone can help me out
Based on the way your method is created , you can do it this way:
def get_result(doc)
doc.each_sli­ce(2).to_a­.map{ |ah| ah if ah[0][:action] == 'Enter'­ && ah[1]­[:action] == 'Leave'­}.compact.flatten
end
Explanation
The variable doc is an array of hashes [hash1, hash2, ...] when we create doc.each_slice(2).to_a will return an array of pair of hashes [[hash1, hash2],[hash3,hash4]...], Now when we do map and get the pair of hashes that has actions per order ('Enter','Leave') we get an array with nil values like this [[hash1,hash2],nil,[hash5,hash6]..] . we use compact to remove the nil values. now the array is like this [[hash1,hash2],[hash5,hash6]..] (array of pair of hashes) and the result expected is an array of hashes, that's why we need flatten, it will remove the inside array and return an array like this [hash1, hash2, hash5, hash6 ...]
If you need to get the list of deleted hashes, i think it would be better if add another method to do it. Otherwise, you can make the get_result method return two arrays.
Here is how you can do it :
def get_result(doc)
removed_elms = []
result = doc.each_sli­ce(2).to_a­.map do |ah|
# if you just need them different (not the first one 'Enter' and the second one 'Leave') you need to set the commented condition
# if ['Enter','Leave'].include?(ah[0][:action] && ah[1][:action]) && ah[0][:action] != ah[1][:action]
if ah[0][:action] == 'Enter'­ && ah[1]­[:action] == 'Leave'
ah
else
removed_elms << ah
nil
end
end.compact
[result.flatten, removed_elms.flatten]
end

Ruby iterate through hash and compare value pairs

My Ruby assignment is to iterate through a hash and return the key associated with the lowest value, without using any of the following methods:
#keys #values #min #sort #min_by
I don't understand how to iterate through the hash and store each pair as it comes through, compare it to the last pair that came through, and return the lowest key. This is my code to show you my thought process, but it of course does not work. Any thoughts on how to do this? Thanks!
def key_for_min_value(name_hash)
index = 0
lowest_hash = {}
name_hash.collect do |key, value|
if value[index] < value[index + 1]
lowest = value
index = index + 1
key_for_min_value[value]
return lowest
end
end
end
Track min_value and key_for_min_value. Iterate through the hash, and any time the current value is lower than min_value, update both of these vars. At the end of the loop, return key_for_min_value.
I didn't include sample code because, hey, this is homework. :) Good luck!
One way to do it is transforming our hash into an array;
def key_for_min_value(name_hash)
# Convert hash to array
name_a = name_hash.to_a
# Default key value
d_value= 1000
d_key= 0
# Iterate new array
name_a.each do |i|
# If current value is lower than default, change value&key
if i[1] < d_value
d_value = i[1]
d_key = i[0]
end
end
return d_key
end
You might need to change d_value to something higher or find something more creative :)
We can use Enumerable#reduce method to compare entries and pick the smallest value. Each hash entry gets passed in as an array with 2 elements in reduce method, hence, I am using Array#first and Array#last methods to access key and values.
h = {"a" => 1, "b" => 2, "c" => 0}
p h.reduce{ |f, s| f.last > s.last ? s : f }.first
#=> "c"

Ruby associative array calculation

I have an associative array in ruby which I want to convert into a hash. This hash will represent the first values as key and sum of their second values as its value.
x = [[1,2],[1,3],[0,1],[0,2],[0,3],[1,5],[0,4],[1,6],[0,9],[1,9]]
How can I get a hash like the following from this associative array?
{
:0 => <sum_of_second_values_with_0_as_first_values>,
:1 => <sum_of_second_values_with_1_as_first_values>
}
It is not very beautiful but it works.
x = [[1,2],[1,3],[0,1],[0,2],[0,3],[1,5],[0,4],[1,6],[0,9],[1,9]]
p Hash[
x.group_by(&:first)
.map do |key, val|
[key,val.map(&:last).inject(:+)]
end
] # => {1=>25, 0=>19}
On second thought, this is simpler:
result = Hash.new(0)
x.each{|item| result[item.first] += item.last}
p result # => {1=>25, 0=>19}
An easy solution using reduce.
It starts with an empty Hash and iterates over all elements of x.
For each pair it adds its value to the hash element at key (if this index wasn't set before, default is 0). The last line sets the memory variable hash for the next iteration.
x.reduce(Hash.new(0)) { |hash, pair|
key, value = pair
hash[key] += value
hash
}
EDIT: set hash default at initialization
x = [[1,2],[1,3],[0,1],[0,2],[0,3],[1,5],[0,4],[1,6],[0,9],[1,9]]
arr_0,arr_1 = x.partition{|a,b| a==0 }
Hash[0,arr_0.map(&:last).inject(:+),1,arr_1.map(&:last).inject(:+)]
# => {0=>19, 1=>25}
or
x = [[1,2],[1,3],[0,1],[0,2],[0,3],[1,5],[0,4],[1,6],[0,9],[1,9]]
hsh = x.group_by{|a| a.first}.each_with_object(Hash.new(0)) do |(k,v),h|
h[k]=v.map(&:last).inject(:+)
end
hsh
# => {1=>25, 0=>19}
each_with_object also works
[[1,2],[1,3],[0,1],[0,2],[0,3],[1,5],[0,4],[1,6],[0,9],[1,9]].
each_with_object(Hash.new(0)) {|(first,last), h| h[first] += last }
# => {1=>25, 0=>19}

Create a hash map from an array that returns the largest value

I have an array of questions where each question has a category_id and a value.
I'd like to map these so that when the key (category_id) already exists in the hash, then the values are added together.
And, finally, I'd like to find the largest value in the hash:
h = Hash.new {|k, v| k[v] = 0}
#test_session.answered_questions.each do |q|
if h.key?(q.category_id)
#add q.value to the value stored in the hash
else
h = { q.category_id => q.value } #insert the "q.category_id" as key and with value "q.value"
end
end
key_with_max_value = h.max_by { |k, v| v }[0] #find the highest value
#result.category = key_with_max_value
#result.score = h[key_with_max_value].value
There is probably a lot better way to achieve this but I'm quite new to Ruby.
h = Hash.new(0)
#test_session.answered_questions.each {|q| h[q.category_id] += q.value}
#result.category, #result.score = h.max_by { |k, v| v }
Each value in the hash will be initialized to zero with Hash.new(0) and since h.max_by returns the key value pair, you can directly assign them to your #result variable.
You can simply do:
#test_session.answered_questions.each { |q| h[q.category_id] += q.value }
When a key is not present, it is assumed to have a value of 0 because of the way you initialized the hash, so it gets inserted with 0 + q.value.
See the documentation, or try it out.
Also, you can assign two variables separated by commas to h.max_by { |k, v| v }. This is called Multiple Assignment, and it works for arrays too:
a,b,c = [1,2,3]

Resources