如何对二维数组求和

How to sum 2-dimensional arrays

我有一个二维数组,其子数组大小相等,例如:

array = [
  [10, 12, 15 ,17], [16, 32, 65, 47], [45, 48, 41, 23],
  [36, 25, 74, 98], [32, 19, 66, 88]
]

我想通过对每第 4 个子数组的相应元素求和来创建一个新数组,即上面示例中 "on top of each other" 的元素:

new_array = [
  [10 + 36, 12 + 25, 15 + 74, 17 + 98],
  [16 + 32, 32 + 19, 65 + 66, 47 + 88],
  [45, 48, 4‌​1, 23]
]

这些只是示例,实际数组可以更大。

完整矩阵

您可以再次使用 each_slice, transpose, map and transpose 来导航您的矩阵。 该代码首先使用 join('+') 来显示正在计算的内容:

array= [[10,12,15,17],[16,32,65,47],[45,48,41,23],[36,25,74,98],[32,19,66,88],[1,2,3,4]]

array.each_slice(3).to_a.transpose.map{|r| r.transpose.map{|x| x.join('+')}}
# => [["10+36", "12+25", "15+74", "17+98"], ["16+32", "32+19", "65+66", "47+88"], ["45+1", "48+2", "41+3", "23+4"]]

array.each_slice(3).to_a.transpose.map{|r| r.transpose.map{|x| x.inject(:+)}}
# => [[46, 37, 89, 115], [48, 51, 131, 135], [46, 50, 44, 27]]

警告!

您需要仔细 select each_slice 参数以适合您的原始数组。 transpose 否则可能会引发异常:

array = [[10,12,15,17],[19,32,65,47],[45,48,41,23],[36,25,74,98],[10,12,15,17],[16,98,65,47],[69,48,65,23],[66,25,74,98]]
array.each_slice(3).to_a.transpose.map{|r| r.transpose.map{|x| x.inject(:+)}}
#=> IndexError: element size differs (2 should be 3)
array.each_slice(4).to_a.transpose.map{|r| r.transpose.map{|x| x.inject(:+)}}
#=> [[20, 24, 30, 34], [35, 130, 130, 94], [114, 96, 106, 46], [102, 50, 148, 196]]

矩阵不完整

如果矩阵 size 不是 width 的倍数:

array = [
  [10, 12, 15 ,17], [16, 32, 65, 47], [45, 48, 41, 23],
  [36, 25, 74, 98], [32, 19, 66, 88]
]

您可以添加全为 0 的子数组以获得:

matrix = [
  [10, 12, 15 ,17], [16, 32, 65, 47], [45, 48, 41, 23],
  [36, 25, 74, 98], [32, 19, 66, 88], [ 0,  0,  0,  0]
]

Array#fill 完成任务:

def maxtrix_column_sums(array, width)
  size    = array.size
  size2   = array.first.size
  missing = (-size) % width
  matrix  = array.dup.fill(Array.new(size2, 0), size...size + missing)
  matrix.each_slice(width).to_a.transpose.map { |r| r.transpose.map { |x| x.join('+') } }
end

p maxtrix_column_sums(array, 3)
#=> [["10+36", "12+25", "15+74", "17+98"], ["16+32", "32+19", "65+66", "47+88"], ["45+0", "48+0", "41+0", "23+0"]]

这是 的变体,使用 zip 而不是 transpose 来说明 "odd" 个子数组:

first, *rest = array.each_slice(3).to_a
first.zip(*rest).map { |r| r.compact.transpose.map { |x| x.inject(:+) } }
#=> [[46, 37, 89, 115], [48, 51, 131, 135], [45, 48, 41, 23]]

工作原理:

each_slice 将数组分成 3 组:

array.each_slice(3).to_a
#=> [
#     [[10, 12, 15, 17], [16, 32, 65, 47], [45, 48, 41, 23]],
#     [[36, 25, 74, 98], [32, 19, 66, 88]]
#   ]

first.zip(*rest) 将第一个切片 "column"-wise 与其余切片组合,在缺少切片时添加 nil

first.zip(*rest)
#=> [
#     [[10, 12, 15, 17], [36, 25, 74, 98]],
#     [[16, 32, 65, 47], [32, 19, 66, 88]],
#     [[45, 48, 41, 23], nil]
#   ]

map / compact / transpose 部分然后重组子数组,同时摆脱 nil 值:

first.zip(*rest).map { |r| r.compact.transpose }
#=> [
#     [[10, 36], [12, 25], [15, 74], [17, 98]],
#     [[16, 32], [32, 19], [65, 66], [47, 88]],
#     [[45],     [48],     [41],     [23]]
#   ]

并且inject(:+)最终对内部元素求和。