Haven't seen this one before, but I was wondering how you can find the sums of both diagonals of a 2D array in Ruby. Say you have a simple array, with 3 rows and 3 columns.
array = [1,2,3,4,5,6,7,8,9]
I can break it into groups of three by using
array.each_slice(3).to_a
Would now be
[1,2,3], [4,5,6], [7,8,9]
[1,2,3]
[4,5,6]
[7,8,9]
In this case, the diagonals are
1 + 5 + 9 = 15
3 + 5 + 7 = 15
So the total sum would be 15 + 15 = 30
I was thinking I could do something like
diagonal_sum = 0
for i in 0..2
for j in 0..2
diagonal_sum += array[i][j]
end
end
Here is my try :
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, i.e. 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
As per the above observation it seems in one iteration you can do solve :
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
Added, OOP style of code :
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
The following is mostly for the academic discussion:
For the main diagonal, you are looking for the "Trace" function which is defined for the "Matrix" class. So the following will work (although it doesn't get you the other diagonal and I wouldn't bet on its efficiency):
require 'Matrix'
a = array.each_slice(3).to_a
Matrix[*a].trace
To get the other diagonal you have to somehow "flip" the matrix, so the following seems to work (Since the result of each_slice
is an array of rows, reverse
reverses the order of the row. Reversing the order of the columns is more difficult):
Matrix[*a.reverse].trace
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With