5
\$\begingroup\$

Would you have any suggestions for improvements for the code below?

def my_transpose(arr)
  # number of rows
  m = arr.count

  #number of columns
  n = arr[0].count

  transposed_arr = Array.new(n) { Array.new(m) }

  # loop through the rows
  arr.each_with_index do |row, index1|

    # loop through the colons of one row
    row.each_with_index do |num, index2|

      # swap indexes to transpose the initial array
      transposed_arr[index2][index1] = num
      p transposed_arr
    end
  end
  transposed_arr
end
\$\endgroup\$
7
\$\begingroup\$

As already mentioned, Ruby's Array comes with a built-in #transpose method.

But, for the purposes of an exercise, there are multiple ways to do the same thing.

For instance, one way (which only works for square matrices!) is to use #map:

def my_transpose(arr)
  arr.each_with_index.map do |_, index|
    arr.map { |row| row[index] }
  end
end

Or you can use reduce (this will work for rectangular matrices):

def my_transpose(arr)
  arr.reduce([]) do |transposed, row|
    row.each_with_index do |value, col|
      transposed[col] ||= []
      transposed[col] << value
    end
    transposed
  end
end

Or do basially the same thing, just using each_with_object:

def my_transpose(arr)
  arr.each_with_object([]) do |row, transposed|
    row.each_with_index do |value, col|
      transposed[col] ||= []
      transposed[col] << value
    end
  end
end

But keeping more of your code, you could use Array#new as your loop, since it accepts a block.

For instance:

def my_transpose(arr)
  rows = arr.count
  cols = arr.first.count
  Array.new(cols) do |col|
    Array.new(rows) do |row|
      arr[row][col]
    end
  end
end

Of course, you'll want to check a few things. Firstly, whether there are any rows in the matrix at all (if not, the arr[0].count will fail), and whether the matrix is actually rectangular:

def my_transpose(arr)
  return [] if arr.empty?

  rows = arr.count
  cols = arr.first.count

  raise ArgumentError unless arr.all? { |row| row.count == cols }

  Array.new(cols) do |col|
    Array.new(rows) do |row|
      arr[row][col]
    end
  end
end

There are yet more ways to do things, but again: It's already built in as arr.transpose.

\$\endgroup\$
  • \$\begingroup\$ Thanks, looking at different ways to do things really help get a grasp of the language. Thx again! \$\endgroup\$ – Andrea.cabral Jun 12 '15 at 22:15
6
\$\begingroup\$

Array#transpose is a built-in Ruby method. Try instead:

p transposed_arr = arr.transpose
\$\endgroup\$
  • \$\begingroup\$ Just to match what the original poster's code does. \$\endgroup\$ – Dan Kohn Apr 16 '15 at 11:40
0
\$\begingroup\$

As mentioned before transpose is a built-in which is fine if don't have space constraint O(N), but if you need O(1) you can do in-place transpose:

def transpose(matrix)
  size = matrix[0].size # assumes square matrix
  (0..(size - 2 )).to_a.each do |y|
    (y..(size - 1)).to_a.each do |x|
      matrix[y][x], matrix[x][y] = matrix[x][y], matrix[y][x]
    end
  end
end 

More about this on wikipedia

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.