Ruby Arrays – 查找对角线的总和

之前没见过这个,但我想知道如何在Ruby中找到2D数组的两个对角线的总和。 假设您有一个简单的数组,包含3行和3列。

array = [1,2,3,4,5,6,7,8,9] 

我可以通过使用将其分为三组

 array.each_slice(3).to_a 

现在会

 [1,2,3], [4,5,6], [7,8,9] [1,2,3] [4,5,6] [7,8,9] 

在这种情况下,对角线是

 1 + 5 + 9 = 15 3 + 5 + 7 = 15 

所以总和将是15 + 15 = 30

我以为我可以做点什么

 diagonal_sum = 0 for i in 0..2 for j in 0..2 diagonal_sum += array[i][j] end end 

这是我的尝试:

 array = [1,2,3,4,5,6,7,8,9] sliced = array.each_slice(3).to_a # As sliced size is 3, I took 2, ie 3 - 1 (0..2).map { |i| sliced[i][i] } #=> [1, 5, 9] (0..2).map { |i| sliced[i][-i-1] } # => [3, 5, 7] (0..2).map { |i| sliced[i][i] }.reduce :+ # => 15 (0..2).map { |i| sliced[i][-i-1] }.reduce :+ # => 15 

根据上述观察结果 ,您可以在一次迭代中解决:

 left_diagonal, right_diagoal = (0..2).each_with_object([[], []]) do |i, a| a[0] << sliced[i][i] a[1] << sliced[i][-i-1] end left_diagonal.reduce(:+) # => 15 right_diagonal.reduce(:+) # => 15 

添加了OOP风格的代码:

 class SquareMatrix attr_reader :array, :order def initialize array, n @array = array.each_slice(n).to_a @order = n end def collect_both_diagonal_elements (0...order).collect_concat { |i| [ array[i][i], array[i][-i-1] ] } end def collect_left_diagonal_elements (0...order).collect { |i| array[i][i] } end def collect_right_diagonal_elements (0...order).collect { |i| array[i][-i-1] } end def sum_of_diagonal_elements type case type when :all then collect_both_diagonal_elements.reduce(0, :+) when :right then collect_right_diagonal_elements.reduce(0, :+) when :left then collect_left_diagonal_elements.reduce(0, :+) end end end array = [1,2,3,4,5,6,7,8,9] sqm = SquareMatrix.new array, 3 sqm.collect_both_diagonal_elements # => [1, 3, 5, 5, 9, 7] sqm.sum_of_diagonal_elements :all # => 30 sqm.collect_left_diagonal_elements # => [1, 5, 9] sqm.sum_of_diagonal_elements :left # => 15 sqm.collect_right_diagonal_elements # => [3, 5, 7] sqm.sum_of_diagonal_elements :right # => 15 

以下主要用于学术讨论:

对于主对角线,您正在寻找为“Matrix”类定义的“跟踪”function。 所以下面的方法会起作用(虽然它没有让你得到另一个对角线,我不会打赌它的效率):

 require 'Matrix' a = array.each_slice(3).to_a Matrix[*a].trace 

要获得另一个对角线,你必须以某种方式“翻转”矩阵,所以以下似乎工作(因为each_slice的结果是一个行数组, reverse反转行的顺序。反转列的顺序更加困难):

 Matrix[*a.reverse].trace 

我完全忘记了#map.with_index …感谢@xlembouras,这是一个单行

 first_diagonal = array.map.with_index {|row, i| row[i]} .inject :+ inverted_diagonal = array.map.with_index {|row, i| row[-i-1]} .inject :+ 

有可能使它成为一个单行:

 first_diagonal, inverted_diagonal = (array.map.with_index {|row, i| row[i]} .inject :+) , (array.map.with_index {|row, i| row[-i-1]} .inject :+) 

原版的:

这是一个想法,这让我觉得有一个#map_with_index方法会很棒:

对于从头到尾的对角线:

 i = -1 array.map { |row| row[i=i+1] }.inject :+ 

对于最后到第一个对角线(假设一个正方形arrays):

 i = array.length array.map { |row| row[i=i-1] }.inject :+ 
 a = [1,2,3,4,5,6,7,8,9] p a.values_at(0,2,4,4,6,8).inject(&:+) #=> 30 

我会尝试迭代数组并根据(分组)数组的长度保留我需要的值

 array = [[1,2,3], [4,5,6], [7,8,9]] dimension = array.length array.flatten.map.with_index do |x,i| x if [0, dimension - 1].include?(i % dimension) end.compact.inject(:+) #=> 30 

您不需要先应用slice

 arr = [1,2,3,4,5,6,7,8,9] 

我们将arr可视化为:

 1 2 3 4 5 6 7 8 9 n = Math.sqrt(arr.size).round #=> 3 

对于主对角线:

 (0...arr.size).step(n+1).reduce(0) { |t,i| t+arr[i] } #=> 15 

对于非对角线:

 (n-1..arr.size-n).step(n-1).reduce(0) { |t,i| t+arr[i] } #=> 15 

另一个例子:

 arr = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6] 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 n = Math.sqrt(arr.size).round #=> 4 (0...arr.size).step(n+1).reduce(0) { |t,i| t+arr[i] } + (n-1..arr.size-n).step(n-1).reduce(0) { |t,i| t+arr[i] } #=> 14 + 14 => 28