从Ruby中的JSON对象检索数据

时间:2016-05-30 22:46:53

标签: ruby-on-rails ruby json

我有一个对象:

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
}

我试图用json.parse(fruit_production)将它转换为JSON对象,但是我怎样才能真正从中获取数据并在之后循环呢?例如:

  1. 返回全年果实产量最高的国家
  2. 返回温暖季节(春季,夏季)果实产量最高的欧洲国家
  3. 返回从国家到年总产量的映射,即{荷兰:1818,泰国:8200等...}
  4. 返回每个地区全球总产量的映射,例如{北:28333,南:91339,东:14343,西:50290}

2 个答案:

答案 0 :(得分:1)

您可以使用to_json

转换为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\":[]}}"

至于从json字符串中检索信息,我认为你最好将其转换回哈希并使用它。

1,3)您可以通过对季节和地区进行求和并获取最大值来获得每个国家的年收益率。

注意:您按区域生成的散列值不必要地复杂 - 您有一个单元素哈希数组,而不是按区域索引的单个哈希值。

目前:[{:north=>nil}, {:south=>"5"}, {:east=>2}, {:west=>"5"}]

更好:{:north=>nil, :south=>"5", :east=>2, :west=>"5"}

然而,这将与你所拥有的一致,虽然我确信它可以简化,(特别是如果你对区域生产结构采取我的建议 - 你有时可以摆脱它 - 混淆inject函数并只对哈希的值求和):

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}
哦,你有领带!我不知道你想对这个案子做什么,但你可以很容易地选择一个最大值:

by_country.max_by { |k,v| v }
=> [:cuba, 19]

2)您可以通过选择fruit_production的元素来获取欧洲国家的fruit_production子集,其中的键(在一些字符串操作之后)与列表中的一个国家/地区名称匹配:

 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=>[]}}

您可以使用它来计算季节性总数。祝其他人好运!

答案 1 :(得分:1)

为了让你开始,它已经很晚了,我确定我错过了什么。有很多方法可以解决这个问题。

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}
#    }

您可以从这些数据中获得您想要的任何内容,例如最高国家/地区或欧洲国家/地区(为此您必须使用array#include?)。

data[:total_highest_profit].max_by {|_, v| v}
# => [:cuba, 19]