Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Arrays - Find the sums of the diagonals

Tags:

arrays

ruby

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
like image 356
Qraider Avatar asked Mar 07 '15 16:03

Qraider


2 Answers

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
like image 121
Arup Rakshit Avatar answered Sep 24 '22 14:09

Arup Rakshit


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
like image 20
nimrodm Avatar answered Sep 24 '22 14:09

nimrodm