Skip to content

Instantly share code, notes, and snippets.

@zaki
Created October 11, 2012 12:39
Show Gist options
  • Save zaki/3872038 to your computer and use it in GitHub Desktop.
Save zaki/3872038 to your computer and use it in GitHub Desktop.
TokyoRails contribute to ruby project for fun: Array#transpose with uneven arrays
static VALUE
rb_ary_transpose_test(VALUE ary)
{
long elen = -1, alen, i, j, k;
VALUE tmp, result = 0;
// get the longest sub-array so we know how much to extend to
long elen_max = -1;
for (i=0; i<alen; i++) {
tmp = to_ary(rb_ary_elt(ary, i));
long length = RARRAY_LEN(tmp);
if (elen_max < length) {
elen_max = length;
}
}
alen = RARRAY_LEN(ary);
if (alen == 0) return rb_ary_dup(ary);
for (i=0; i<alen; i++) {
tmp = to_ary(rb_ary_elt(ary, i));
if (elen < 0) { /* first element */
elen = RARRAY_LEN(tmp);
result = rb_ary_new2(elen);
for (j=0; j<elen; j++) {
rb_ary_store(result, j, rb_ary_new2(alen));
}
}
for (j=0; j<elen; j++) {
long len = RARRAY_LEN(tmp);
if (len < elen_max) {
if (!rb_block_given_p()) {
rb_raise(rb_eIndexError, "element size differs (%ld should be %ld) and no block was given",
RARRAY_LEN(tmp), elen);
}
else {
for(k = len; k < elen_max; k++) {
// fill in missing elements
VALUE filler = rb_yield(rb_ary_new3(2L, LONG2FIX(i), LONG2FIX(k)));
rb_ary_push_1(tmp, filler);
}
}
}
rb_ary_store(rb_ary_elt(result, j), i, rb_ary_elt(tmp, j));
}
}
return result;
}
rb_define_method(rb_cArray, "transpose_test", rb_ary_transpose_test, 0);
require 'test/unit'
class TestArray < Test::Unit::TestCase
def setup
@verbose = $VERBOSE
$VERBOSE = nil
@cls = Array
end
def teardown
$VERBOSE = @verbose
end
# LOTS OF OTHER TESTS
def test_transpose
assert_equal([[1, :a], [2, :b], [3, :c]],
[[1, 2, 3], [:a, :b, :c]].transpose_test)
assert_raise(IndexError) { [[1, 2, 3], [:a, :b]].transpose_test }
end
def test_transpose_with_block
assert_equal([[1, :a], [2, :b], [3, :hoge]],
[[1,2,3], [:a, :b]].transpose_test { |x, y| :hoge })
end
def test_transpose_block_parameters
[[1, :a], [2, :b], [3]].transpose_test do |x, y|
assert_equal(2, x)
assert_equal(1, y)
:foo
end
end
def test_transpose_block_parameters
arr = [[1, nil, :a], [nil, :b], [3]].transpose_test do |x, y|
:foo
end
assert_equal([
[1, nil, 3],
[nil, :b ,:foo],
[:a, :foo, :foo]
], arr)
end
#LOTS OF OTHER TESTS
end
@randym
Copy link

randym commented Oct 11, 2012

class TestArray < Test::Unit::TestCase
  def setup
    @verbose = $VERBOSE
    $VERBOSE = nil
    @cls = Array
  end

  def teardown
    $VERBOSE = @verbose
  end

  # LOTS OF OTHER TESTS

  def test_transpose
    assert_equal([[1, :a], [2, :b], [3, :c]],
      [[1, 2, 3], [:a, :b, :c]].transpose)
    assert_raise(IndexError) { [[1, 2, 3], [:a, :b]].transpose }
  end

  def test_transpose_with_block
    assert_equal([[1, :a], [2, :b], [3, :hoge]],
           [[1,2,3], [:a, :b]].transpose { |x, y| :hoge }
  end

  def test_transpose_block_parameters
    [[1, :a] [2, :b], [3]].transpose do |x, y|
      assert_equal(3, x)
      assert_equal(2, y)
    end
  end

  #LOTS OF OTHER TESTS
end

@randym
Copy link

randym commented Oct 11, 2012

module Transposer
def self.transpose array
return array.clone if array.size == 0
rows = array.size
columns = array.map { |item| item.size }.max
result = Array.new(columns) { Array.new(rows) }
0...rows.times do |row_index|
0...columns.times do |column_index|
result[column_index][row_index] =
if array.size > row_index && array[row_index].size > column_index
array[row_index][column_index]
elsif block_given?
yield(column_index, row_index)
else
raise ArgumentError, 'your array sucks'
end
end
end
result
end
end

require 'test/unit'
class TestTransposer < Test::Unit::TestCase

def test_transpose_empty
assert(Transposer::transpose(Array.new).is_a?(Array))
end

def test_transpose_simple
assert_equal(Transposer.transpose([[1,2], [3,4]]), [[1, 3], [2, 4]])
end

def test_transpose_with_block
assert_equal(Transposer.transpose([[1], [3, 4]]) { |x, y| 2 },
[[1,3],[2,4]])
end

end

@randym
Copy link

randym commented Oct 11, 2012

module Transposer
  def self.transpose array
    return array.clone if array.size == 0
    rows = array.size
    columns = array.map { |item| item.size }.max
    result = Array.new(columns) { Array.new(rows) }
    0...rows.times do |row_index|
     0...columns.times do |column_index|
       result[column_index][row_index] = 
         if array.size > row_index && array[row_index].size > column_index 
            array[row_index][column_index]
         elsif block_given?
           yield(column_index, row_index)
         else
           raise ArgumentError, 'your array sucks'
         end
      end
    end
    result
  end
end

require 'test/unit'
class TestTransposer < Test::Unit::TestCase

  def test_transpose_empty
    assert(Transposer::transpose(Array.new).is_a?(Array))
  end

  def test_transpose_simple
    assert_equal(Transposer.transpose([[1,2], [3,4]]), [[1, 3], [2, 4]])
  end

  def test_transpose_with_block
    assert_equal(Transposer.transpose([[1], [3, 4]]) { |x, y| 2 },
            [[1,3],[2,4]])
  end

end


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment