Rubyのネストされたハッシュ内の同じキーの値を平均する
概要
次のようなネストされたハッシュがあります。
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 を持つ 1 つのハッシュになり、各キーには元のハッシュの対応する値の平均が含まれるようにしたいと考えています。
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}
mergeとmapを使用しようとしましたが、この結果を達成するために使用できるより効率的なブロックはありますか?
これまでのところ、私はこのルートをたどってきました。
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
解決策
基本的にここでできることは、配列をフラット化してサブ配列を削除し、各ハッシュ キーのすべての値を配列に収集することです。
次に、各配列を平均します。
# 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 }