编辑我接受@ CarySwoveland的答案,因为他在第一次尝试时得到了最接近的,占大多数情况,并将数据输出到哈希中,这样您就不需要依赖订购。尽管如此,许多人都可以提及!如果你想要输出数组,请务必查看@ ArupRakshit的答案!
我有一系列哈希,如:
@my_hashes = [{"key1" => "10", "key2" => "5"...},{"key1" => "", "key2" => "9"...},{"key1" => "6", "key2" => "4"...}]
我希望数组中每个键的平均值。即。 8.0,6.0...
请注意,即使键的值为空,散列也按顺序具有完全相同的键。现在这个有用:
<%= @my_hashes[0].keys.each do |key| %>
<% sum = 0 %>
<% count = 0 %>
<% @my_hashes.each do |hash| %>
<% sum += hash[key].to_f %>
<% count += if hash[key].blank? then 0 else 1 end %>
<% end %>
<%= (sum/count) %>
<% end %>
但我觉得可能有更好的方法......任何想法?
答案 0 :(得分:2)
执行以下操作
@my_hashes = [{"key1" => "10", "key2" => "5"},{"key1" => "", "key2" => "9"},{"key1" => "6", "key2" => "4"}]
ar = @my_hashes[0].keys.map do |k|
a = @my_hashes.map { |h| h[k].to_f unless h[k].blank? }.compact
a.inject(:+)/a.size unless a.empty? #Accounting for "key1" => nil or "key1" => ""
end
ar # => [8, 6]
答案 1 :(得分:1)
我想我找到了一个非常优雅的解决方案。
以下是一个示例数组:
a = [
{:a => 2, :b => 10},
{:a => 4, :b => 20},
{:a => 2, :b => 10},
{:a => 8, :b => 40},
]
解决方案:
class Array
def average
self.reduce(&:+) / self.size
end
end
r = a[0].keys.map do |key|
[key, a.map { |hash| hash[key] }.average]
end
puts Hash[*r.flatten]
答案 2 :(得分:1)
试试这个
@my_hashes = [{"key1" => "10", "key2" => "5"},{"key1" => "", "key2" => "9"},{"key1" => "6", "key2" => "4"}]
average_values = @my_hashes.map(&:values).transpose.map { |arr|
arr.map(&:to_f).inject(:+) / arr.size
}
with_keys = Hash[@my_hashes.first.keys.zip(average_values)]
average_values # => [5.333333333333333, 6.0]
with_keys # => {"key1"=>5.333333333333333, "key2"=>6.0}
如果要从平均值中排除空值,可以更改average_values以拒绝空值
average_values = @my_hashes.map(&:values).transpose.map { |arr|
arr.reject!(&:empty?)
arr.map(&:to_f).inject(:+) / arr.size
}
average_values # => [8.0, 6.0]
答案 3 :(得分:1)
另一种方式:
@my_hashes = [ {"key1"=>"10", "key2"=>"5"},
{"key1"=> "", "key2"=>"9"},
{"key1"=> "6", "key2"=>"4"} ]
def avg(arr) arr.any? ? arr.reduce(:+)/arr.size.to_f : 0.0 end
(@my_hashes.each_with_object ( Hash.new { |h,k| h[k]=[] } ) {
|mh,h| mh.keys.each { |k| h[k] << mh[k].to_f unless mh[k].empty? } })
.each_with_object({}) { |(k,v),h| h[k] = avg(v) }
# => {"key1"=>8.0, "key2"=>6.0}
第一个each_with_object
创建的对象是一个哈希,其默认值为空数组。该哈希由块变量h
表示。这意味着,如果h[k] << mh[k].to_f
执行h.key?(k) => false
,则首先执行h[k] = []
。
可以选择删除avg
方法并在计算平均值之前创建一个临时变量:
h = @my_hashes.each_with_object ( Hash.new { |h,k| h[k]=[] } ) { |mh,h|
mh.keys.each { |k| h[k] << mh[k].to_f unless mh[k].empty? } }
h.each_with_object({}) { |(k,v),h|
h[k] = ( avg(v) arr.any? ? arr.reduce(:+)/arr.size.to_f : 0.0 }
答案 4 :(得分:0)
没有超级干净的解决方案,但我会写:
a = [
{:a => 2, :b => 10},
{:a => 4, :b => 20},
{:a => 2, :b => 10},
{:a => 8, :b => 40},
]
grouped = a.flat_map(&:to_a).group_by{|x,|x}
grouped.keys.each do |key|
len = grouped[key].size
grouped[key] = 1.0 * grouped[key].map(&:last).inject(:+) / len
end