按数组中的键分组并获得最大值和平均值

时间:2017-08-31 05:25:43

标签: ruby-on-rails

我有一个结构就是这样的数组:

{"status": "ok", "data": [{"temp": 22, "wind": 351.0, "datetime": "20160815-0330"}, {"temp": 21, "wind": 321.0, "datetime": "20160815-0345"}]}

我希望按datetime键分组(忽略时间),找到最大temp和平均wind

我尝试了以下内容,但不确定如何在同一张地图中执行max_by和average:

@data['data'].group_by { |d| d.values_at("datetime") }.map { |_, v| v.max_by { |h| h["temp"] } }

2 个答案:

答案 0 :(得分:1)

因此,当您执行data时,@data[:data].group_by { |data| data[:datetime].split('-')[0] } 实际上会变成符号,而不是字符串,因此您需要执行以下操作:

:datetime

为了按-键分组,忽略时间部分(我假设,时间部分只是{"20160815"=>[{:temp=>22, :wind=>351.0, :datetime=>"20160815-0330"}, {:temp=>21, :wind=>321.0, :datetime=>"20160815-0345"}]} 之后的所有内容)。然后你最终看起来像哈希:

:temp

并找到您可以执行的:wind的最大results = @data[:data].group_by { |data| data[:datetime].split('-')[0] }.map do |date, values| [date, { maximum_temp: values.max_by { |value| value[:temp] }[:temp], average_wind: values.sum { |value| value[:wind] }.to_f / values.length }] end.to_h # => {"20160815"=>{:maximum_temp=>22, :average_wind=>336.0}} 和平均值:

Objects

答案 1 :(得分:0)

上面的方法效果很好,使用 max_by 并访问值 [:temp] 然后求和和显式 to_h 即可。因此,如果您考虑到性能和良好的可读性,您可以使用基本的每个,如下所示,

data = {"20160815"=>[{:temp=>22, :wind=>351.0, :datetime=>"20160815-0330"}, {:temp=>21, :wind=>321.0, :datetime=>"20160815-0345"}]}
data.map do |k, v|                                                                                                                                                                     
  winds = []                                                                                                                                                                           
  temps = []                                                                                                                                                                           
  v.each do |item|                                                                                                                                                                       
    winds << item[:wind]                                                                                                                                                                 
    temps << item[:temp]                                                                                                                                                               
  end                                                                                                                                                                                  
  {k => {max_temp: temps.max, avg_wind: winds.inject(:+).to_f/winds.length}}                                                                                                         
end

输出低于,

# => {"20160815"=>{:max_temp=>22, :avg_wind=>336.0}}

以下是使用 each和max_by 之间的小基准,

data = {"20160815"=>[{:temp=>22, :wind=>351.0, :datetime=>"20160815-0330"}, {:temp=>21, :wind=>321.0, :datetime=>"20160815-0345"}]}


def by_each(data)
  data.map do |k, v|
    winds = []
    temps = []
    v.each do |item|
      winds << item[:wind]
      temps << item[:temp]
    end
    {k => {max_temp: temps.max, avg_wind: winds.inject(:+).to_f/winds.length}}
  end
end

def by_max(data)
  data.map do |date, values|
    [date, {
       maximum_temp: values.max_by { |value| value[:temp] }[:temp],
       average_wind: values.sum { |value| value[:wind] }.to_f / values.length
     }]
  end.to_h
end

Benchmark.ips do |x|                                                                                                                                                                   
  x.config(times: 10)                                                                                                                                                                  
  x.report 'BY_EACH' do                                                                                                                                                                  
    by_each(data)                                                                                                                                                                      
  end
  x.report 'BY_MAX' do                                                                                                                                                                   
    by_max(data)                                                                                                                                                                       
  end                                                                                                                                                                                  
  x.compare!                                                                                                                                                                         
end

基准o / p如下所示,

Warming up --------------------------------------
             BY_EACH    18.894k i/100ms
              BY_MAX    13.793k i/100ms
Calculating -------------------------------------
             BY_EACH    226.160k (± 5.3%) i/s -      1.134M in   5.025488s
              BY_MAX    154.745k (± 5.8%) i/s -    772.408k in   5.006365s

Comparison:
             BY_EACH:   226159.5 i/s
              BY_MAX:   154744.8 i/s - 1.46x  slower

因此,您可以看到BY_MAX比BY_EACH慢1.46倍。但是,当然,您可以使用任何适合您的理解和可用性的方法。