如何对几个数组的对应元素进行求和?

时间:2021-10-28 19:37:31

I have several arrays of various lengths, each with a 2-item array within it. For example:

我有几个不同长度的数组,每个数组都有两个条目。例如:

[["12:00", 7.0], ["01:00", 3.3], ["02:00", 11.9], ["03:00", 56.5]]

or

[["12:00", 44.3], ["01:00", 2.25], ["02:00", 2.44], ["03:00", 46.11], ["04:00", 8.9], ["05:00", 18.187]]

I want to loop through, and add the corresponding elements of each array, into a new array. The output array will be the length of the longest array we're adding together.

我要循环,并将每个数组的相应元素添加到一个新的数组中。输出数组将是我们加在一起的最长数组的长度。

So the two arrays above summed together would output the following:

所以上面两个数组相加会得到如下结果:

[["12:00", 51.3], ["01:00", 5.55], ["02:00", 14.34], ["03:00", 102.61], ["04:00", 8.9], ["05:00", 18.187]]

I don't think I can use reduce() or inject() since I don't want to collapse the array, nor is the array a simple array of elements.

我不认为可以使用reduce()或inject(),因为我不想折叠数组,数组也不是简单的元素数组。

I really have no idea how I might approach this problem.

我真的不知道该如何处理这个问题。

2 个解决方案

#1


4  

You can do it in one line with Hash.merge. Use a block to sum the values during the merge.

你可以在一行中使用hash。merge。在合并期间使用块来求和值。

def sum_arrays(a, b)
  Hash[a].merge(Hash[b]){|k, i, j| i + j}.to_a
end

Output:

输出:

a = [["12:00", 7.0], ["01:00", 3.3], ["02:00", 11.9], ["03:00", 56.5]]
b = [["12:00", 44.3], ["01:00", 2.25], ["02:00", 2.44], ["03:00", 46.11], ["04:00", 8.9], ["05:00", 18.187]]    
sum_arrays(a,b)

=> [["12:00", 51.3], ["01:00", 5.55], ["02:00", 14.34], ["03:00", 102.61], ["04:00", 8.9], ["05:00", 18.187]]

To sum more than two arrays, add one more line:

若要将两个以上的数组相加,请再加一行:

def sum_many_arrays(*a)
  a.reduce{|s, i| sum_arrays(s, i)}
end

Output:

输出:

sum_many_arrays([[:a,1],[:b,2]],[[:a,2],[:b,2],[:c,1]],[[:a,5],[:b,2]])
=> [[:a, 8], [:b, 6], [:c, 1]] 

#2


0  

I recommend @Oleg's approach, but there's always another way:

我推荐@Oleg的方法,但总有另一种方法:

arr = [[["12:00",  7.0], ["01:00",  3.3], ["02:00", 11.9], ["03:00", 56.5]],
       [["12:00", 44.3], ["01:00", 2.25], ["02:00", 2.44], ["03:00", 46.11],
        ["04:00",  8.9]],
       [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]]]

keys = arr.reduce([]) { |keys,a| keys | a.map(&:first) }
arr.map { |a| a.to_h.values_at(*keys) }
   .transpose
   .map { |e| [keys.shift, e.reduce(0) { |tot,x| tot + x.to_f }] }
  #=> [["12:00",   64.6], ["01:00", 27.8], ["02:00", 16.18],
  #    ["03:00", 102.61], ["04:00",  8.9]] 

The steps:

的步骤:

keys = arr.reduce([]) { |keys,a| keys | a.map(&:first) }
  #=> ["12:00", "01:00", "02:00", "03:00", "04:00"] 
b = arr.map { |a| a.to_h.values_at(*keys) }
  #=> [[ 7.0,   3.3, 11.9,  56.5, nil],
  #    [44.3,  2.25, 2.44, 46.11, 8.9],
  #    [13.3, 22.25, 1.84,   nil, nil]] 
c = b.transpose
  #=> [[7.0,   44.3,  13.3],
  #    [3.3,   2.25, 22.25],
  #    [11.9,  2.44,  1.84],
  #    [56.5, 46.11,   nil],
  #    [nil,    8.9,   nil]]
c.map { |e| [keys.shift, e.reduce(0) { |tot,x| tot + x.to_f }] }
  #=> [["12:00",   64.6], ["01:00", 27.8], ["02:00", 16.18],
  #    ["03:00", 102.61], ["04:00",  8.9]] 

Notice that NilClass#to_f converts nil to 0.0.

注意,NilClass#to_f将nil转换为0.0。

To elaborate the calculation of b above:

详细说明上述b的计算:

d = arr.map
  #=> #<Enumerator: [[["12:00",   7.0], ["01:00",  3.3], ["02:00", 11.9],
  #                   ["03:00",  56.5]],
  #                  [["12:00",  44.3], ["01:00", 2.25], ["02:00", 2.44],
  #                   ["03:00", 46.11], ["04:00",  8.9]],
  #                  [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]]]:map> 

a = d.next
  #=> [["12:00", 7.0], ["01:00", 3.3], ["02:00", 11.9], ["03:00", 56.5]] 
e = a.to_h
  #=> {"12:00"=>7.0, "01:00"=>3.3, "02:00"=>11.9, "03:00"=>56.5} 
f = e.values_at(*keys)
  #=> e.values_at(*["12:00", "01:00", "02:00", "03:00", "04:00"] ) 
  #=> [7.0, 3.3, 11.9, 56.5, nil] 

a = d.next
  #=> [["12:00",  44.3], ["01:00", 2.25], ["02:00", 2.44],
  #    ["03:00", 46.11], ["04:00",  8.9]] 
e = a.to_h
  #=> {"12:00"=> 44.3, "01:00"=>2.25, "02:00"=>2.44,
  #    "03:00"=>46.11, "04:00"=> 8.9} 
f = e.values_at(*keys)
  #=> [44.3, 2.25, 2.44, 46.11, 8.9] 

a = d.next
  #=> [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]] 
e = a.to_h
  #=> {"01:00"=>22.25, "02:00"=>1.84, "12:00"=>13.3} 
f = e.values_at(*keys)
  #=> [13.3, 22.25, 1.84, nil, nil] 

c.map is computed as follows:

c。地图计算如下:

keys = ["12:00", "01:00", "02:00", "03:00", "04:00"] 

d = c.map
  #=> #<Enumerator: [[ 7.0, 44.3, 13.3], [3.3, 2.25, 22.25],
  #                  [11.9, 2.44, 1.84], [56.5, 46.11, nil],
  #                  [nil, 8.9, nil]]:map> 

e = d.next
  #=> [7.0, 44.3, 13.3] 
f = keys.shift
  #=> "12:00" 
keys
  #=> ["01:00", "02:00", "03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 64.6

e = d.next
  #=> [3.3, 2.25, 22.25] 
f = keys.shift
  #=> "01:00" 
keys
  #=> ["02:00", "03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 27.8 

e = d.next
  #=> [11.9, 2.44, 1.84] 
f = keys.shift
  #=> "02:00" 
keys
  #=> ["03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 16.18 

e = d.next
  #=> [56.5, 46.11, nil] 
f = keys.shift
  #=> "03:00" 
keys
  #=> ["04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 102.61 

e = d.next
  #=> [nil, 8.9, nil] 
f = keys.shift
  #=> "04:00" 
keys
  #=> [] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 8.9 

#1


4  

You can do it in one line with Hash.merge. Use a block to sum the values during the merge.

你可以在一行中使用hash。merge。在合并期间使用块来求和值。

def sum_arrays(a, b)
  Hash[a].merge(Hash[b]){|k, i, j| i + j}.to_a
end

Output:

输出:

a = [["12:00", 7.0], ["01:00", 3.3], ["02:00", 11.9], ["03:00", 56.5]]
b = [["12:00", 44.3], ["01:00", 2.25], ["02:00", 2.44], ["03:00", 46.11], ["04:00", 8.9], ["05:00", 18.187]]    
sum_arrays(a,b)

=> [["12:00", 51.3], ["01:00", 5.55], ["02:00", 14.34], ["03:00", 102.61], ["04:00", 8.9], ["05:00", 18.187]]

To sum more than two arrays, add one more line:

若要将两个以上的数组相加,请再加一行:

def sum_many_arrays(*a)
  a.reduce{|s, i| sum_arrays(s, i)}
end

Output:

输出:

sum_many_arrays([[:a,1],[:b,2]],[[:a,2],[:b,2],[:c,1]],[[:a,5],[:b,2]])
=> [[:a, 8], [:b, 6], [:c, 1]] 

#2


0  

I recommend @Oleg's approach, but there's always another way:

我推荐@Oleg的方法,但总有另一种方法:

arr = [[["12:00",  7.0], ["01:00",  3.3], ["02:00", 11.9], ["03:00", 56.5]],
       [["12:00", 44.3], ["01:00", 2.25], ["02:00", 2.44], ["03:00", 46.11],
        ["04:00",  8.9]],
       [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]]]

keys = arr.reduce([]) { |keys,a| keys | a.map(&:first) }
arr.map { |a| a.to_h.values_at(*keys) }
   .transpose
   .map { |e| [keys.shift, e.reduce(0) { |tot,x| tot + x.to_f }] }
  #=> [["12:00",   64.6], ["01:00", 27.8], ["02:00", 16.18],
  #    ["03:00", 102.61], ["04:00",  8.9]] 

The steps:

的步骤:

keys = arr.reduce([]) { |keys,a| keys | a.map(&:first) }
  #=> ["12:00", "01:00", "02:00", "03:00", "04:00"] 
b = arr.map { |a| a.to_h.values_at(*keys) }
  #=> [[ 7.0,   3.3, 11.9,  56.5, nil],
  #    [44.3,  2.25, 2.44, 46.11, 8.9],
  #    [13.3, 22.25, 1.84,   nil, nil]] 
c = b.transpose
  #=> [[7.0,   44.3,  13.3],
  #    [3.3,   2.25, 22.25],
  #    [11.9,  2.44,  1.84],
  #    [56.5, 46.11,   nil],
  #    [nil,    8.9,   nil]]
c.map { |e| [keys.shift, e.reduce(0) { |tot,x| tot + x.to_f }] }
  #=> [["12:00",   64.6], ["01:00", 27.8], ["02:00", 16.18],
  #    ["03:00", 102.61], ["04:00",  8.9]] 

Notice that NilClass#to_f converts nil to 0.0.

注意,NilClass#to_f将nil转换为0.0。

To elaborate the calculation of b above:

详细说明上述b的计算:

d = arr.map
  #=> #<Enumerator: [[["12:00",   7.0], ["01:00",  3.3], ["02:00", 11.9],
  #                   ["03:00",  56.5]],
  #                  [["12:00",  44.3], ["01:00", 2.25], ["02:00", 2.44],
  #                   ["03:00", 46.11], ["04:00",  8.9]],
  #                  [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]]]:map> 

a = d.next
  #=> [["12:00", 7.0], ["01:00", 3.3], ["02:00", 11.9], ["03:00", 56.5]] 
e = a.to_h
  #=> {"12:00"=>7.0, "01:00"=>3.3, "02:00"=>11.9, "03:00"=>56.5} 
f = e.values_at(*keys)
  #=> e.values_at(*["12:00", "01:00", "02:00", "03:00", "04:00"] ) 
  #=> [7.0, 3.3, 11.9, 56.5, nil] 

a = d.next
  #=> [["12:00",  44.3], ["01:00", 2.25], ["02:00", 2.44],
  #    ["03:00", 46.11], ["04:00",  8.9]] 
e = a.to_h
  #=> {"12:00"=> 44.3, "01:00"=>2.25, "02:00"=>2.44,
  #    "03:00"=>46.11, "04:00"=> 8.9} 
f = e.values_at(*keys)
  #=> [44.3, 2.25, 2.44, 46.11, 8.9] 

a = d.next
  #=> [["01:00", 22.25], ["02:00", 1.84], ["12:00", 13.3]] 
e = a.to_h
  #=> {"01:00"=>22.25, "02:00"=>1.84, "12:00"=>13.3} 
f = e.values_at(*keys)
  #=> [13.3, 22.25, 1.84, nil, nil] 

c.map is computed as follows:

c。地图计算如下:

keys = ["12:00", "01:00", "02:00", "03:00", "04:00"] 

d = c.map
  #=> #<Enumerator: [[ 7.0, 44.3, 13.3], [3.3, 2.25, 22.25],
  #                  [11.9, 2.44, 1.84], [56.5, 46.11, nil],
  #                  [nil, 8.9, nil]]:map> 

e = d.next
  #=> [7.0, 44.3, 13.3] 
f = keys.shift
  #=> "12:00" 
keys
  #=> ["01:00", "02:00", "03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 64.6

e = d.next
  #=> [3.3, 2.25, 22.25] 
f = keys.shift
  #=> "01:00" 
keys
  #=> ["02:00", "03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 27.8 

e = d.next
  #=> [11.9, 2.44, 1.84] 
f = keys.shift
  #=> "02:00" 
keys
  #=> ["03:00", "04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 16.18 

e = d.next
  #=> [56.5, 46.11, nil] 
f = keys.shift
  #=> "03:00" 
keys
  #=> ["04:00"] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 102.61 

e = d.next
  #=> [nil, 8.9, nil] 
f = keys.shift
  #=> "04:00" 
keys
  #=> [] 
e.reduce(0) { |tot,x| tot + x.to_f }
  #=> 8.9