有几种方法可以做到这一点。这是一个使用方法Hash#update(又名merge!)的形式,它使用一个块来确定被合并的两个散列中存在的键的值:
a.each_with_object({}) { |g,h|
h.update(g["order_detail_id"]=>g) { |_,oh,ng|
{ "order_detail_id" =>g["order_detail_id"],
"quantity"=>oh["quantity"]+ng["quantity"] } } }.values
#=> [{"order_detail_id"=>236, "quantity"=>2},
# {"order_detail_id"=>237, "quantity"=>1}]
另一种方法使用Enumerable#group_by:
a.group_by { |h| h["order_detail_id"] }.map { |id, a|
{ "order_detail_id"=>id, "quantity"=>a.reduce(0) { |t,g|
t + g["quantity"] } } }
#=> [{"order_detail_id"=>236, "quantity"=>2},
# {"order_detail_id"=>237, "quantity"=>1}]
编辑:monoy 询问如何合并:
a = [{236=>1}, {236=>1}, {237=>1}]
当您拥有带有单个键值对的哈希时,通常最简单的方法是首先将它们转换为数组,以便轻松访问键和值:
b = a.map(&:to_a)
#=> [[[236, 1]], [[236, 1]], [[237, 1]]]
不幸的是,这有三层数组,而我们只需要两层。我们可以这样写:
b = a.map(&:to_a).flatten(1)
#=> [[236, 1], [236, 1], [237, 1]]
但更简单的方法是:
b = a.flat_map(&:to_a)
#=> [[236, 1], [236, 1], [237, 1]]
同样,我们可以用几种不同的方式合并数组。这是一个使用默认值为零的哈希:
b.each_with_object(Hash.new(0)) { |(k,v),h| h[k] += v }
#=> {236=>2, 237=>1}
我们有:
enum = b.each_with_object(Hash.new(0))
#=> #<Enumerator: [[236, 1], [236, 1], [237, 1]]:each_with_object({})>
我们可以把这个枚举器转换成一个数组,看看each会传入什么值:
enum.to_a
#=> [[[236, 1], {}], [[236, 1], {}], [[237, 1], {}]]
我们可以使用Enumerator#next获取枚举器的每个值,并将块变量分配给该值。第一个传递给块的是:
(k,v),h = enum.next
#=> [[236, 1], {}]
k #=> 236
v #=> 1
h #=> {}
所以在我们执行的块中:
h[k] += v
计算结果为:
h[236] += 1
意思是:
h[236] = h[236] + 1
哈希 h 目前为空,因此它没有密钥 236。因此,表达式右侧的h[236] 返回哈希的默认值零:
h[236] = 0 + 1
现在:
h #=> {236=>1}
现在将下一个元素传递到块中:
(k,v),h = enum.next
#=> [[236, 1], {236=>1}]
k #=> 236
v #=> 1
h #=> {236=>1}
所以现在我们在块中执行表达式时不使用默认值:
h[k] += v
#=> h[k] = h[k] + v
#=> h[236] = h[236] + 1
#=> h[236] = 1 + 1
现在:
h #=> {236=>2}
现在将枚举器的第三个也是最后一个元素传递给块:
(k,v),h = enum.next
#=> [[237, 1], {236=>2}]
k #=> 237
v #=> 1
h #=> {236=>2}
h[k] += v
#=> h[k] = h[k] + v
#=> h[237] = h[237] + 1
#=> h[236] = 0 + 1 # the default value of 0 applies
h #=> {236=>2, 237=>1}
我们已经完成了。