Ruby中嵌套哈希中相同键的平均值

nxagd54h  于 12个月前  发布在  Ruby
关注(0)|答案(3)|浏览(74)

我有一个嵌套的哈希,看起来像这样:

main_hash = [[
  {"a"=>{:x=>70.1}, "b"=>{:x=>97.17}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.05}, "b"=>{:x=>97.17}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.12}, "b"=>{:x=>97.17}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.08}, "b"=>{:x=>97.17}, "c"=>{:x=>97.23}}]]

我想最终得到一个具有相同键a...f的散列,每个键都有一个对应的原始散列值的平均值:

return_hash = {"a" => average of all the values[:x] corresponding to "a" in each hash, 
"b" => average of all the values[:x] corresponding to "b" in each hash,
"c" => average of all the values[:x] corresponding to "c" in each hash}

我尝试使用mergemap,但有没有更有效的块可以实现这个结果?
到目前为止,我一直在走这条路:

keys = []
          values = []
          divider = main_hash.size 
          iteration = main.first.first.size
          iteration.times do
              sum = 0
              keys << main_hash.first[0].first[0]
              main_hash.each do |f|
                f.each do |g|
                  sum += g.dig(cores.keys.first, :x)
                  g.shift
                end
              end
              values << ((sum / divider).round(2))
          ret_hash = keys.zip(values).to_h
r8uurelv

r8uurelv1#

基本上,你可以在这里做的就是将数组扁平化以删除子数组,然后将每个哈希键的所有值收集到一个数组中。
然后求每个数组的平均值。

# loop through the outer array and return a hash
main_hash.flatten.each_with_object({}) do |hash, memo|
  # loop over the keys and values of the hash
  hash.each_pair do |name, value|
    memo[name] ||= []
    memo[name].push(value.dig(:x))
  end
end # {"a"=>[70.1, 70.05, 70.12, 70.08], ... }
  # loop across the values and convert the array to an average
  .transform_values { |ary| ary.sum / ary.length } 
  # {"a"=>70.0875, "b"=>97.17, "c"=>97.245}

也可以使用Hash#merge!

main_hash.flatten.each_with_object({}) do |hash, memo|
  memo.merge!(hash) do |key, old, new|
   (old.is_a?(Hash) ? old.values_at(:x) : old).push(new[:x])
  end
end.transform_values { |ary| ary.sum / ary.length }
ulydmbyx

ulydmbyx2#

这将是有帮助的,看看你已经提出了什么解决方案,到目前为止,看看我们是否可以改善它。你可以使用each_with_object来尝试这样的操作:

# Create a hash to store sum and count of each key
totals = main_hash.each_with_object(Hash.new { |hash, key| hash[key] = { sum: 0.0, count: 0 } }) do |h, acc|
  h.each do |key, value|
    acc[key][:sum] += value[:x]
    acc[key][:count] += 1
  end
end

# Calculate average for each key
return_hash = {}
totals.each do |key, value|
  return_hash[key] = value[:sum] / value[:count]
end

puts return_hash

它将输出:

{"a"=>70.08749999999999, "b"=>97.17, "c"=>97.245}
qyswt5oh

qyswt5oh3#

首先,我修改了main_hash,以表明计算平均值的值的数量不需要对所有键都相同(即,示例中的"a""b""c")。

main_hash = [
  [{"a"=>{:x=>70.1},  "b"=>{:x=>97.17}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.05}, "b"=>{:x=>97.17}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.12}, "b"=>{:x=>96.11}, "c"=>{:x=>97.25}}], 
  [{"a"=>{:x=>70.08}, "b"=>{:x=>97.17}}]
]

我还将main_hash[2].first[:b][x]更改为96.11,因此所有“"b"的值“都不相同。
我将计算平均值如下(有点类似于@dlmb的解决方案,尽管我不构造数组)。

main_hash.each_with_object({}) do |(g),h|
  g.each do |k,f|
    h.update(k=>{ tot: f.values.first, n: 1.0 }) do |_k,o,n|
      o.merge(tot: o[:tot] + n[:tot], n: o[:n] + 1) 
    end
  end
end.transform_values { |g| g[:tot]/g[:n] }
  #=> {"a"=>70.08749999999999, "b"=>96.905, "c"=>97.25}

这里transform_values的接收器被发现等于以下。

{"a"=>{:tot=>280.34999999999997, :n=>4.0}, "b"=>{:tot=>387.62, :n=>4.0},
 "c"=>{:tot=>291.75, :n=>3.0}}

相关问题