How do I summarize hashes within a hash?
hashmap, ruby
Solution
First and foremost don't use upper-case letters for variables in Ruby as you did with `SomeHash` and `XPath`. When a variable name starts with an upper-case letter, it means it's a constant and you probably didn't want it to be a constant.
`each` is not the best way to do this, you can do this much more simply with `inject` as in:
countries = {
"Albania"=>"Europe",
"Andorra"=>"Europe",
"Austria"=>"Europe",
"Lebanon"=>"Asia",
"Macau"=>"Asia",
"Malaysia"=>"Asia",
"Papua New Guinea"=>"Asia",
"Jamaica"=>"North America",
"Martinique"=>"North America",
"Argentina"=>"South America",
"Chile"=>"South America",
"Sao Tome and Principe"=>"Africa",
"Senegal"=>"Africa",
"Somalia"=>"Africa"}
by_continents = countries.inject({}) do |memo, (k,v)|
memo[v] ||= []
memo[v] << k
memo
end
The output for this is:
{"Europe"=>["Albania", "Andorra", "Austria"], "Asia"=>["Lebanon", "Macau", "Malaysia", "Papua New Guinea"], "North America"=>["Jamaica", "Martinique"], "South America"=>["Argentina", "Chile"], "Africa"=>["Sao Tome and Principe", "Senegal", "Somalia"]}
You have all countries grouped by continent and you can pick any one of them.
In your code it should be placed like this:
def country
inflation_hash = {}
XPath.match( data, "//country").map do |element|
inflation_hash[element.attributes["name"]] = element.attributes["continent"]
end
by_continents = inflation_hash.inject({}) do |memo, (k,v)|
memo[v] ||= []
memo[v] << k
memo
end
puts by_continents.inspect
by_continents
end
Problem
I have a hash like this: ``` Some_hash = {"Albania"=>"Europe", "Andorra"=>"Europe", "Austria"=>"Europe", Lebanon"=>"Asia", "Macau"=>"Asia", "Malaysia"=>"Asia", "Papua New Guinea"=>"Asia", "Jamaica"=>"North America", "Martinique"=>"North America", "Argentina"=>"South America", "Chile"=>"South America", "Sao Tome and Principe"=>"Africa", "Senegal"=>"Africa", "Somalia"=>"Africa",} ``` I would like to identify the five continents individually, and the countries that belong to them, such that I end up with something like this: ``` {"Africa" => ["Senegal", "Somalia"]} {"Europe" => ["Albania", "Andorra", "Austria"]} ``` for all of the continents. I tried this: ``` def country inflation_hash = {} XPath.match( data, "//country").map do |element| inflation_hash[element.attributes["name"]] = element.attributes["continent"] end inflation_hash.each do |country, continent| new_hash = {} if inflation_hash.has_value?("Africa") == true new_hash["Africa"] = inflation_hash.keys puts new_hash end end end ``` and it works much too well. I get a new hash: ``` {Africa => []} ``` but I have two problems: - I create a new hash for each African country. - Each new hash contains all the keys, which includes all non-African countries. I think the first problem has to do with the `each` method so I have to set some conditional, right? The second problem, I have no idea how to fix. Any pointers would be greater appreciated.