Reputation: 2099
I have an object:
EURO_COUNTRIES = ['France', 'Germany', 'Spain']
fruit_production = {
cuba: {
#meaning: country c produces k kilograms of fruit in region r for season s
winter: [{north: 1}, {south: nil}, {east: 4}, {west: 4}],
summer: [{north: nil}, {south: 5}, {east: ""}, {west: 5}],
},
spain: {
fall: [{north: 7}, {}],
summer: [{north: nil}, {south: "5"}, {east: 2}, {west: '5'}],
spring: []
}
#and the list goes on for hundreds of countries
}fruit_production = {
cuba: {
#meaning: country c produces k kilograms of fruit in region r for season s
winter: [{north: 1}, {south: nil}, {east: 4}, {west: 4}],
summer: [{north: nil}, {south: 5}, {east: ""}, {west: 5}],
},
spain: {
fall: [{north: 7}, {}],
summer: [{north: nil}, {south: "5"}, {east: 2}, {west: '5'}],
spring: []
}
#and the list goes on for hundreds of countries
}
I tried to convert it to JSON object with json.parse(fruit_production), but how can I can actually get the data from it and loop it after that? For example:
Upvotes: 1
Views: 448
Reputation: 2302
To get you started off, it's late and I'm sure I've missed something. There are plenty of ways going about this as well.
data = fruit_production.each_with_object(Hash.new {|k,v| k[v] = Hash.new(0)}) do |(country, seasons), memo|
seasons.each do |season, regions|
regions.each do |region|
fruit_yield = Integer(region.values.first) rescue 0
memo[:total_highest_profit][country] += fruit_yield
memo[:total_region_yield][region.keys.first] += fruit_yield if region.keys.first
memo[:total_warm_season][country] += fruit_yield if season == :summer || season == :spring
end
end
end
# => {
# :total_region_yield=>{:north=>8, :south=>10, :east=>6, :west=>14},
# :total_highest_profit=>{:cuba=>19, :spain=>19},
# :total_warm_season=>{:cuba=>10, :spain=>12}
# }
You can get whatever you want from this data, such as highest country or European country (for this you'll have to use array#include?).
data[:total_highest_profit].max_by {|_, v| v}
# => [:cuba, 19]
Upvotes: 1
Reputation: 4604
you can convert to json with to_json
> fruit_production.to_json
=> "{\"cuba\":{\"winter\":[{\"north\":1},{\"south\":null},{\"east\":4},{\"west\":4}],\"summer\":[{\"north\":null},{\"south\":5},{\"east\":\"\"},{\"west\":5}]},\"spain\":{\"fall\":[{\"north\":7},{}],\"summer\":[{\"north\":null},{\"south\":\"5\"},{\"east\":2},{\"west\":\"5\"}],\"spring\":[]}}"
As for retrieving the info from a json string, I think you're better off just to convert it back to a hash and work with that.
1, 3) You can get the yearly yield for each country by summing over season and region and taking the max.
note: your hash of yield by region is unnecessarily complex - you have an array of single-element hashes instead of a single hash indexed by region.
current: [{:north=>nil}, {:south=>"5"}, {:east=>2}, {:west=>"5"}]
better: {:north=>nil, :south=>"5", :east=>2, :west=>"5"}
However, this will work with what you've got, though I'm sure it can be simplified, (especially if you take my recommendation on the region-production structure - you can get rid of the sometimes-confusing inject
function and just sum on the values of the hash):
by_country = Hash[fruit_production.map { |country, production| [country, production.map {|season, data| data.inject(0) { |sum, v| sum + v.values.map(&:to_i).sum } }.sum]}]
=> {:cuba=>19, :spain=>19}
Uh oh, you have a tie! I don't know what you want to do with that case, but you can just select one max pretty easily:
by_country.max_by { |k,v| v }
=> [:cuba, 19]
2) You can get a subset of fruit_production for European countries by selecting the elements of fruit_production whose key (after some string manipulation) matches one of the country names in the list:
euro_fruit_production = fruit_production.select {|k,v| EURO_COUNTRIES.include?(k.to_s.titleize)}
=> {:spain=>{:fall=>[{:north=>7}, {}], :summer=>[{:north=>nil}, {:south=>"5"}, {:east=>2}, {:west=>"5"}], :spring=>[]}}
you can use that to work out seasonal totals. Good luck with the rest!
Upvotes: 1