我有这样的哈希:
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",}
我想单独确定五大洲以及属于他们的国家,这样我最终会得到这样的结论:
{"Africa" => ["Senegal", "Somalia"]}
{"Europe" => ["Albania", "Andorra", "Austria"]}
适用于所有大陆。
我试过了:
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
它的效果非常好。我得到一个新的哈希:
{Africa => []}
但我有两个问题:
我认为第一个问题与each
方法有关,所以我必须设置一些条件,对吧?
第二个问题,我不知道如何修复。
任何指针都会更受欢迎。
答案 0 :(得分:3)
首先,不要像使用SomeHash
和XPath
那样在Ruby中使用大写字母表示变量。当变量名以大写字母开头时,它意味着它是一个常数,你可能不希望它是一个常数。
each
不是最好的方法,您可以使用inject
更简单地执行此操作,如下所示:
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
这个输出是:
{"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"]}
您所有国家/地区都按大陆分组,您可以选择其中任何一个。
在您的代码中,它应该像这样放置:
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
答案 1 :(得分:1)
以下是我解决问题的方法:
def sort_by_continents
# Initialize example Hash of countries:
country_map = {"Albania"=>"Europe", "Andorra"=>"Europe",
"Lebanon"=>"Asia", "Macau"=>"Asia",
"Jamaica"=>"North America", "Chile"=>"South America",
"Senegal"=>"Africa", "Malaysia"=>"Asia"}
# Create a new Hash where initial values are = []
continent_map = Hash.new{|h,k| h[k] = []}
# For each country in the initial hash:
# Add the corresponding country to the appropriate continent.
country_map.each {|country,continent| continent_map[continent] << country}
# Return the continent map.
continent_map
end
记忆肯定是最好和最有效的方法(如上所述),但对于初学者,我说从一些有意义的事情开始。一旦你花了更多时间在Ruby上,就会有记忆和优化 - 我知道当我开始时,inject
和||=
的概念令人难以置信。从基础开始始终是最好的方法。
答案 2 :(得分:0)
您可以在构建inflation_hash
的同时执行此操作,只需使用default_proc
on the Hash to auto-vivify个新元素作为空数组:
inflation_hash = { }
new_hash = Hash.new { |h, k| h[k] = [ ] }
XPath.match(data, "//country").map do |element|
name, continent = element.attributes.values_at('name', 'continent')
inflation_hash[name] = continent
new_hash[continent].push(name)
end
这将使您获得inflation_hash
,因为您现在拥有它并new_hash
喜欢:
{
"Africa" => ["Senegal", "Somalia"],
"Europe" => ["Albania", "Andorra", "Austria"],
...
}
答案 3 :(得分:0)
你已经有了哈希,所以为什么不做你需要的地方:
countries.keys.each { |k|
(countries[countries.delete(k)] ||= []) << k
}
如果您的国家/地区的名称与大陆完全相同,则会失败,但对您来说不是这样,对吗?
答案 4 :(得分:0)
我会考虑两种方式:
version1 = countries.each_with_object({}) do |(key,value),result|
(result[value] ||= []) << key
end
version2 = Hash[countries.group_by(&:last).map{|x,y|[x,y.map(&:first)]}]