2017-06-15 132 views
-1

我有一個哈希陣列來自一個發電機表,我需要通過一個密鑰進行分組並彙總另一個密鑰的值。我的陣列類似於:紅寶石合併哈希陣列基於密鑰,哈希另一個密鑰的總和值

data = [ 
    { 'state' => 'Florida', 'minutes_of_sun' => 10, 'timestamp' => 1497531600, 'region' => 'Southeast' }, 
    { 'state' => 'Florida', 'minutes_of_sun' => 7, 'timestamp' => 1497531600, 'region' => 'Southeast' }, 
    { 'state' => 'Florida', 'minutes_of_sun' => 2, 'timestamp' => 1497531600, 'region' => 'Southeast' }, 
    { 'state' => 'Georgia', 'minutes_of_sun' => 15, 'timestamp' => 1497531600, 'region' => 'Southeast' }, 
    { 'state' => 'Georgia', 'minutes_of_sun' => 5, 'timestamp' => 1497531600, 'region' => 'Southeast' } 
] 

,我要尋找的最終結果是:

data = [ 
    { 'state' => 'Florida', 'minutes_of_sun' => 19, 'region' => 'Southeast' }, 
    { 'state' => 'Georgia', 'minutes_of_sun' => 20, 'region' => 'Southeast' } 
] 

我已經能夠通過我下面寫了一個方法來做到這一點,但它是緩慢的,笨重。想知道是否有更快/更少的LoC方式來做到這一點?

def combine_data(data) 
    combined_data = [] 

    data.each do |row| 
    existing_data = combined_data.find { |key| key['state'] == row['state'] } 
    if existing_data.present? 
     existing_data['minutes_of_sun'] += row['minutes_of_sun'] 
    else 
     combined_data << row 
    end 
    end 

    combined_data 
end 
+0

'data.group_by {| H | h ['state']} .values.map {| hs | hs.inject {| a,b | a.merge(b){| key,oldval,newval | oldval + newval}}}' – falsetru

+0

'data.group_by {| h | h ['state']} .values.map {| hs | hs.inject {| a,b | a ['minutes_of_sun'] + = b ['minutes_of_sun']; (如果你不介意修改原來的'data'哈希值) – falsetru

+0

[哈希數組中的Sum值如果它們具有相同的值,可能重複](https://stackoverflow.com/questions/43876712/) sum-values-in-hash-array-of-hash-if-they-have-the-the-value)這個問題已經被多次詢問和回答(你是否先嚐試搜索?)只是Google搜索給我帶來了幾十個結果而沒有看太難 – engineersmnky

回答

1

嘗試這一個

data.group_by { |item| item['state'] }.values.map do |arr| 
    h = arr.first 
    h.delete('timestamp') 
    h.merge('minutes_of_sun' => arr.inject { |acc, h| acc + h['minutes_of_sun'] }) 
end 
=> [{"state"=>"Florida", "minutes_of_sun"=>19, "region"=>"Southeast"}, {"state"=>"Georgia", "minutes_of_sun"=>20, "region"=>"Southeast"}] 

從紅寶石2.4.0

data.group_by { |item| item['state'] }.values.map do |arr| 
    h = arr.first 
    h.delete('timestamp') 
    h.merge('minutes_of_sun' => arr.sum { |item| item['minutes_of_sun'] }) 
end 
=> [{"state"=>"Florida", "minutes_of_sun"=>19, "region"=>"Southeast"}, {"state"=>"Georgia", "minutes_of_sun"=>20, "region"=>"Southeast"}] 
0

可以使用的Hash#update(又名merge!)的形式,其使用一個塊,以確定密鑰的值這兩個哈希都在合併中。請參閱文檔以獲取該塊中三個塊變量的解釋。

data = [ 
    { 'state'=>'Florida', 'sun_min'=>10, 'stamp'=>149, 'region'=>'SE' }, 
    { 'state'=>'Georgia', 'sun_min'=>15, 'stamp'=>149, 'region'=>'SE' }, 
    { 'state'=>'Georgia', 'sun_min'=> 5, 'stamp'=>149, 'region'=>'SE' } 
] 

data.each_with_object({}) do |g,h| 
    h.update(g['state']=>g.reject { |k,_| k=='stamp' }) do |_,o,n| 
    o.merge('sun_min'=>o['sun_min']+n['sun_min']) 
    end 
end.values 
    #=> [{"state"=>"Florida", "sun_min"=>10, "region"=>"SE"}, 
    # {"state"=>"Georgia", "sun_min"=>20, "region"=>"SE"}] 

注意,如果沒有這個.values返回

#=> {"Florida"=>{"state"=>"Florida", "sun_min"=>10, "region"=>"SE"}, 
# "Georgia"=>{"state"=>"Georgia", "sun_min"=>20, "region"=>"SE"}}