Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby getting the diagonal elements in a 2d Array

I was trying some problems with my 2D ruby array and my LOC reduces a lot when I do array slicing. So for example,

require "test/unit"

class LibraryTest < Test::Unit::TestCase

  def test_box
    array = [[1,2,3,4],[3,4,5,6], [5,6,7,8], [2,3,4,5]]
    puts array[1][2..3] # 5, 6
    puts array[1..2][1] # 5, 6, 7, 8
  end
end

I want to know if there is a way to get a diagonal slice? Lets say I want to start at [0,0] and want a diagonal slice of 3. Then I would get elements from [0,0], [1,1], [2,2] and I will get an array like [1,4,7] for example above. Is there any magic one-liner ruby code that can achieve this? 3.times do {some magic stuff?}

like image 890
Kannan Ekanath Avatar asked Mar 24 '10 09:03

Kannan Ekanath


3 Answers

puts (0..2).collect { |i| array[i][i] }
like image 157
YOU Avatar answered Sep 22 '22 06:09

YOU


Better might be a one-liner that utilizes the Matrix library:

require 'matrix'
Matrix.rows(array).each(:diagonal).to_a
like image 34
zilla Avatar answered Sep 19 '22 06:09

zilla


I'm picking up @Shai's answer and propose to make it more functional.

First we initialize the array:

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

Then we prepare the array which serves as padding:

padding = [*0..(arr.length - 1)].map { |i| [nil] * i }
=> [[], [nil], [nil, nil], [nil, nil, nil]]

Then we apply the padding to the array. If you reverse the first usage of the padding or the second one depends if you want to get downward or upward diagonals.

padded = padding.reverse.zip(arr).zip(padding).map(&:flatten)
=> [[nil, nil, nil, 1, 2, 3, 4], [nil, nil, 3, 4, 5, 6, nil], [nil, 5, 6, 7, 8, nil, nil], [2, 3, 4, 5, nil, nil, nil]]

Then we transpose as in @Shai's solution:

padded.transpose.map(&:compact)
=> [[2], [5, 3], [3, 6, 4], [1, 4, 7, 5], [2, 5, 8], [3, 6], [4]]
like image 35
schmijos Avatar answered Sep 19 '22 06:09

schmijos