HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Transposing a 2D array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
arraytransposingstackoverflow

Problem

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

Solution

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.

Code Snippets

def my_transpose(arr)
  arr.each_with_index.map do |_, index|
    arr.map { |row| row[index] }
  end
end
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
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
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
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

Context

StackExchange Code Review Q#87043, answer score: 7

Revisions (0)

No revisions yet.