2014-10-02 34 views

回答

3

如果:

array = [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}] 

,那麼你可以這樣做:

array.inject(Hash.new{|h,k| h[k] = 0}) 
     { |h, a| k, v = a.flatten; h[k] += v; h }. 
     map{|arr| Hash[*arr] } 
#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}] 

或:

array.each_with_object(Hash.new{|h,k| h[k] = 0}) 
     { |a, h| k, v = a.flatten; h[k] += v }. 
     map{|arr| Hash[*arr] } 
#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}] 
+1

'#each_with_object'就是我要找如果使用或不使用任何一個來完成。 :-)但是你做到了,所以你節省了我的時間..:P +1 – 2014-10-02 08:05:45

+1

1.你不需要'to_a'。 (爲什麼?)。 2.你不需要'; h'與'each_with_object'(這就是@Arup建議後者的原因)。 3.「arr」是一個合適的名字嗎?該格式大大改善。 – 2014-10-02 15:26:44

+0

@CarySwoveland是的正是..這就是爲什麼我不使用'#注入',如果我不被迫.. .. P – 2014-10-02 15:33:21

1

有很多方法可以做到這一點。看到一些甚至是一些可能不尋常和/或不是特別有效的東西是有益的。

這裏是另一種方式:

arr = [{"a"=>1},{"b"=>2},{"c"=>3},{"a"=>2},{"b"=>4}] 

arr.flat_map(&:keys) 
    .uniq 
    .map { |k| { k=>arr.reduce(0) { |t,g| t + (g.key?(k) ? g[k] : 0) } } } 
    #=> [{"a"=>3}, {"b"=>6}, {"c"=>3}] 

由於nil.to_i => 0,我們可以改爲寫reduce的塊爲:

{ |t,g| t+g[k].to_i } 
1

要在不是一比一的方式來轉換集合每一次,它是#reduce工作。對於一對一轉換,我們使用#map

array.reduce({}) { |h, acc| acc.merge(h) {|_k, o, n| o+n } }.zip.map(&:to_h) 
# => [{"b"=>6}, {"a"=>3}, {"c"=>3}] 

在這裏,我們使用與初始值{},其被傳遞到塊作爲acc參數減少,然後我們使用#merge具有手動「解決衝突」。這意味着僅當我們試圖合併的密鑰已經存在於方法接收器acc中時纔會調用該塊。之後,我們將哈希分解爲哈希數組。

+0

你需要添加'。{{| k,v | {k => v}}'或者類似於結尾的東西,將結果轉換爲指定的形式(散列數組)。 – 2014-10-02 06:55:49

+0

它應該產生:'[{「a」=> 3},{「b」=> 6},{「c」=> 3}]'不是'{「b」=> 6,「a」=> 3,「c」=> 3}'。我認爲你需要做一些像@CarySwoveland提到的事情。 – Surya 2014-10-02 07:02:01

+0

這也是一個好方法。謝謝。 – 2014-10-02 09:50:24

2

它可以如下

array.group_by { |h| h.keys.first }. 
values. 
map {|x| x.reduce({}) { |h1, h2| h1.merge(h2) { |_, o, n| o + n } } 

#=> [{"a"=>3}, {"b"=>6}, {"c"=>3}] 
相關問題