編輯:自從我第一次發佈我的答案以來,問題已被澄清。結果,我大大修改了我的答案。
下面是解決這個問題的兩種「標準」方法。兩者都使用Enumerable#select首先從包含給定鍵/值對的數組(哈希)中提取元素。
#1
第一種方法使用Hash#merge!到每個數組元素(散列)順序地合併成一個散列最初爲空的。
代碼
def doit(arr, target_key, target_value)
qualified = arr.select {|h|h.key?(target_key) && h[target_key]==target_value}
return nil if qualified.empty?
qualified.each_with_object({}) {|h,g|
g.merge!(h) {|k,gv,hv| k == target_key ? gv : (gv.to_i + hv.to_i).to_s}}
end
例
arr = [{:id => '1', :value => '2'}, {:id => '2', :value => '3'},
{:id => '1', :chips => '4'}, {:zd => '1', :value => '8'},
{:cat => '2', :value => '3'}, {:id => '1', :value => '5'}]
doit(arr, :id, '1')
#=> {:id=>"1", :value=>"7", :chips=>"4"}
說明
這裏的關鍵是使用採用了塊的Hash#merge!
版本,以確定該值每個鍵/ VA其中的鍵出現在兩個哈希中的lue pair被合併。該密鑰的兩個值由塊變量hv
和gv
表示。我們只是想將它們加在一起。請注意,g
是由each_with_object
創建並由doit
返回的(最初爲空)散列對象。
target_key = :id
target_value = '1'
qualified = arr.select {|h|h.key?(target_key) && h[target_key]==target_value}
#=> [{:id=>"1", :value=>"2"},{:id=>"1", :chips=>"4"},{:id=>"1", :value=>"5"}]
qualified.empty?
#=> false
qualified.each_with_object({}) {|h,g|
g.merge!(h) {|k,gv,hv| k == target_key ? gv : (gv.to_i + hv.to_i).to_s}}
#=> {:id=>"1", :value=>"7", :chips=>"4"}
#2
其他常見的方式做這種計算是使用Enumerable#flat_map,其次是Enumerable#group_by。
代碼
def doit(arr, target_key, target_value)
qualified = arr.select {|h|h.key?(target_key) && h[target_key]==target_value}
return nil if qualified.empty?
qualified.flat_map(&:to_a)
.group_by(&:first)
.values.map { |a| a.first.first == target_key ? a.first :
[a.first.first, a.reduce(0) {|tot,s| tot + s.last}]}.to_h
end
說明
這可能看起來複雜,但如果你將它分解爲步驟它不是那麼糟糕。這是發生了什麼。 (中qualified
計算是一樣#1)
target_key = :id
target_value = '1'
c = qualified.flat_map(&:to_a)
#=> [[:id,"1"],[:value,"2"],[:id,"1"],[:chips,"4"],[:id,"1"],[:value,"5"]]
d = c.group_by(&:first)
#=> {:id=>[[:id, "1"], [:id, "1"], [:id, "1"]],
# :value=>[[:value, "2"], [:value, "5"]],
# :chips=>[[:chips, "4"]]}
e = d.values
#=> [[[:id, "1"], [:id, "1"], [:id, "1"]],
# [[:value, "2"], [:value, "5"]],
# [[:chips, "4"]]]
f = e.map { |a| a.first.first == target_key ? a.first :
[a.first.first, a.reduce(0) {|tot,s| tot + s.last}] }
#=> [[:id, "1"], [:value, "7"], [:chips, "4"]]
f.to_h => {:id=>"1", :value=>"7", :chips=>"4"}
#=> {:id=>"1", :value=>"7", :chips=>"4"}
評論
你不妨從qualified
在哈希整數考慮出不來的價值觀和排除target_key/target_value
雙:
arr = [{:id => 1, :value => 2}, {:id => 2, :value => 3},
{:id => 1, :chips => 4}, {:zd => 1, :value => 8},
{:cat => 2, :value => 3}, {:id => 1, :value => 5}]
target_key = :id
target_value = 1
qualified = arr.select { |h| h.key?(target_key) && h[target_key]==target_value}
.each { |h| h.delete(target_key) }
#=> [{:value=>2}, {:chips=>4}, {:value=>5}]
return nil if qualified.empty?
然後要麼
qualified.each_with_object({}) {|h,g| g.merge!(h) { |k,gv,hv| gv + hv } }
#=> {:value=>7, :chips=>4}
或
qualified.flat_map(&:to_a)
.group_by(&:first)
.values
.map { |a| [a.first.first, a.reduce(0) {|tot,s| tot + s.last}] }.to_h
#=> {:value=>7, :chips=>4}
你可能需要與你的鑰匙一致的是,他們的字符串或符號 – bjhaid
執行陣列中的所有哈希值有':id'和':value'鍵,是id總是1? – 2014-03-28 00:09:42
我猜你喜歡* sum *具有特定':id'的散列的':value'屬性,就像你在SQL語句'SELECT SUM(value)FROM Hashes GROUP BY id'中得到的那樣,如果你得到了我意思。你能澄清一下嗎? – Patru