我了解在ruby中,我们可以将像这样的数组中的元素求和
[1,2,3].sum
[<Object a: 1>, <Object a:2>].sum(&:a)
如何对对象数组中的多个属性求和。例如:
arr = [<Object a:1, b:2, ..., n:10>, <Object a:1, b:2, ..., n:10>, ... <nth Object>]
获取多个属性a,b,... n的总和的最有效方法是什么?
我尝试了以下方法:
sum_a = arr.sum(&:a)
sum_b = arr.sum(&:b)
a, b = 0, 0
arr.each do |obj|
a += obj.a
b += obj.b
end
我想知道是否有更好的方法可以解决这个问题。
答案 0 :(得分:2)
您可以为此创建自己的方法:
def sum_multiple(arr, *keys)
arr.each_with_object(keys.zip([0] * keys.size).to_h) do |o,obj|
keys.each {|k| obj[k] += o.public_send(k)}
end
end
用法:
class A
attr_reader :a,:b,:c
def initialize(a,b,c)
@a,@b,@c = a,b,c
end
end
arr = 10.times.map {|i| A.new(i,i*2,i*3)}
sum_multiple(arr,:a)
#=> {:a=>45}
sum_multiple(arr,:a,:b)
#=> {:a=>45, :b=>90}
sum_multiple(arr,:a,:b,:c)
#=> {:a=>45, :b=>90, :c=>135}
"Sum of everything: #{sum_multiple(arr,:a,:b,:c).sum(&:last)}"
#=> "Sum of everything: 270"
注意::如果这是Rails,则应研究group by和sum的组合并将其放在数据库中。
答案 1 :(得分:1)
如果您只希望对某些键值求和,则可以执行以下操作:
[{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}].flat_map{|h| h.slice(:a, :b).values}.sum
或者,如果您想对所有值求和,
[{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}].flat_map(&:values).sum
对于可能不是散列的对象
arr.sum {|o| [:a, :b, :c].sum{ |key| o.send key} }
答案 2 :(得分:1)
让我们从创建实例数组开始。
class C
def initialize(a,b,c)
@a, @b, @c = a, b, c
end
end
arr = [[1,2,3], [4,5,6], [7,8,9]].map { |a| C.new(*a) }
#=> [#<C:0x00005a4282c2d980 @a=1, @b=2, @c=3>,
# #<C:0x00005a4282c2d5c0 @a=4, @b=5, @c=6>,
# #<C:0x00005a4282c2d3b8 @a=7, @b=8, @c=9>]
然后
ivs = arr.first.instance_variables
#=> [:@a, :@b, :@c]
arr.map { |i| ivs.map { |v| i.instance_variable_get(v) } }.
transpose.
map(&:sum)
#=> [12, 15, 18]
步骤如下。
a = arr.map { |i| ivs.map { |v| i.instance_variable_get(v) } }
#=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
b = a.transpose
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
c = b.map(&:sum)
#=> [12, 15, 18]
如果需要标签:
ivs = arr.first.instance_variables
ivs.zip(arr.map {|i| ivs.map {|v| i.instance_variable_get(v)}}.
transpose.
map(&:sum)).
to_h
#=> {:@a=>12, :@b=>15, :@c=>18}
如果只需要某些实例变量的总和,例如@a
和@c
,则只需更改ivs
:
ivs = [:@a, :@c]
ivs.zip(arr.map {|i| ivs.map {|v| i.instance_variable_get(v)}}.
transpose.
map(&:sum)).
to_h
#=> {:@a=>12, :@c=>18}