![](/img/trans.png)
[英]Ruby group_by an array of hashes with different keys(keys are not fixed)
[英]Group array of hashes by multiple keys to find average in Ruby
我已經找到解決問題的解決方案,但是我需要在Ruby(RoR)中完成。 這是問題和解決方案的鏈接: 使用多個分組依據查找哈希數組的平均值
所以我有一個哈希數組,需要按鍵(首先subject_id
然后element_id
)進行分組,然后找到它們的平均值。 數組中的哈希數不固定。
下面是輸入數組:
a=[
{:subject_id=>1, :element_id=>2, :value=>55},
{:subject_id=>1, :element_id=>4, :value=>33},
{:subject_id=>1, :element_id=>2, :value=>33},
{:subject_id=>1, :element_id=>4, :value=>1},
{:subject_id=>1, :element_id=>2, :value=>7},
{:subject_id=>1, :element_id=>4, :value=>4},
{:subject_id=>2, :element_id=>2, :value=>3},
{:subject_id=>2, :element_id=>2, :value=>5},
{:subject_id=>2, :element_id=>4, :value=>9}
]
結果:
b=[
{:subject_id=>1, :element_id=>2, :value=>95},
{:subject_id=>1, :element_id=>4, :value=>38},
{:subject_id=>2, :element_id=>2, :value=>8},
{:subject_id=>2, :element_id=>4, :value=>9}
]
我建議使用計數哈希來獲取鍵:value
的小計,然后從該哈希構造所需的哈希數組。 這使用Hash#new的形式,該形式采用的參數是哈希的默認值。 這意味着,如果哈希h
沒有鍵k
,則h[k]
返回默認值。
計算總數
a.each_with_object(Hash.new(0)) {|g,h| h[[g[:subject_id], g[:element_id]]] += g[:value]}.
map {|(sub, el), tot| { subject_id: sub, element_id: el, value: tot}}
#=> [{:subject_id=>1, :element_id=>2, :value=>95},
# {:subject_id=>1, :element_id=>4, :value=>38},
# {:subject_id=>2, :element_id=>2, :value=>8},
# {:subject_id=>2, :element_id=>4, :value=>9}]
第一步,將Ruby解壓縮表達式
h[[g[:subject_id], g[:element_id]]] += g[:value]
更改為
h[[g[:subject_id], g[:element_id]]] = h[[g[:subject_id], g[:element_id]]] + g[:value]
如果h
沒有等號右側的鍵[g[:subject_id], g[:element_id]]
, h[[g[:subject_id], g[:element_id]]]
,則返回默認值0
。
注意
a.each_with_object(Hash.new(0)) {|g,h| h[[g[:subject_id], g[:element_id]]] += g[:value]}
#=> {[1, 2]=>95, [1, 4]=>38, [2, 2]=>8, [2, 4]=>9}
計算平均值
僅需很小的變化即可計算平均值。
a.each_with_object({}) do |g,h|
pair = [g[:element_id], g[:subject_id]]
h[pair] = {tot: 0, count: 0} unless h.key?(pair)
h[pair] = {tot: h[pair][:tot] + g[:value], count: h[pair][:count]+1}
end.map {|(sub, el),h| {subject_id: sub, element_id: el,
average: (h[:tot].to_f/h[:count]).round(1)}}
#=> [{:subject_id=>2, :element_id=>1, :average=>31.7},
# {:subject_id=>4, :element_id=>1, :average=>12.7},
# {:subject_id=>2, :element_id=>2, :average=>4.0},
# {:subject_id=>4, :element_id=>2, :average=>9.0}]
注意
a.each_with_object({}) do |g,h|
pair = [g[:element_id], g[:subject_id]]
h[pair] = {tot: 0, count: 0} unless h.key?(pair)
h[pair] = {tot: h[pair][:tot] + g[:value], count: h[pair][:count]+1}
end
#=> {[2, 1]=>{:tot=>95, :count=>3}, [4, 1]=>{:tot=>38, :count=>3},
# [2, 2]=>{:tot=> 8, :count=>2}, [4, 2]=>{:tot=> 9, :count=>1}}
問題中顯示的結果不是平均值,而是總和,因此結果將有所不同:
def groupByAndAverage(a)
b = []
a.each_with_index do |element, key|
index = b.index do |x|
x != element &&
x[:subject_id] == element[:subject_id] &&
x[:element_id] == element[:element_id]
end
if index
b[index][:value] += element[:value]
b[index][:amount] += 1
else
b.push a[key].merge(amount: 1)
end
true
end
b.map do |element|
element[:value] = element[:value] / element[:amount]
element.delete(:amount)
element
end
b
end
結果是:
[{:subject_id=>1, :element_id=>2, :value=>31},
{:subject_id=>1, :element_id=>4, :value=>12},
{:subject_id=>2, :element_id=>2, :value=>4},
{:subject_id=>2, :element_id=>4, :value=>9}]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.