Create a gist now

Instantly share code, notes, and snippets.

Array#transpose that accepts a block for populating missing elements
class Array
# A more meaningful message when you have an insufficient number of columns
# in a row for transposition.
MSG_TRANSPOSE_INDEX_ERROR = "Row %s has only %s element(s), but transposition
requires %s. Please specify a block to populate missing items or adjust
your array to contain an equal number of elements in each row array."
# Overrides the default transpose method to allow a block that can be used to return
# elements required to populate the transposition.
# @example Using Transpose
# > [[1, 2], [3, 4]].transpose
# => [[1, 3], [2, 4]]
#
# > [[1], [3, 4]].transpose
# IndexError: Row 0 has only 1 element(s), but transposition requires 2...
#
# > [[1,], [3, 4]].transpose { |x, y| 2 }
# => [[1, 3], [2, 4]]
# @note
# When yielding to the block the column(x) and row(y) index for the
# missing element are provided
# @return [Array] The transposed array
def transpose
return clone if size == 0
rows = size
columns = map(&:size).max
result = Array.new(columns) { Array.new(rows) }
0...rows.times do |row_index|
0...columns.times do |column_index|
datum = if self[row_index].size > column_index
self[row_index][column_index]
elsif block_given?
yield(column_index, row_index)
else
raise IndexError, MSG_TRANSPOSE_INDEX_ERROR %
[row_index,
self[row_index].size,
columns]
end
result[column_index][row_index] = datum
end
end
result
end
end
require 'test/unit'
class TestArray < Test::Unit::TestCase
def test_transpose_empty
assert(Array.new.transpose.is_a?(Array))
end
def test_transpose_simple
assert_equal([[1, 2], [3, 4]].transpose,
[[1, 3], [2, 4]])
end
def test_transpose_with_block
filled = [[1], [3, 4]].transpose { |x, y| 2 }
assert_equal([[1, 3],[2, 4]], filled)
end
def test_your_array_sucks
assert_raise(IndexError) do
[[1, 2], [1]].transpose
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment