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