地方でリモートワーク

プログラミング、先物、fx,仮想通貨なんでもやります

Rubyで要素数が異なる配列をtransposeする6つの方法(ベンチマークとテスト付き)

スポンサーリンク

f:id:ihatov08:20171003121303j:plain

Rubyで要素数が異なる配列をtransposeする6つの方法です。(ベンチマークとテスト付きです)

コード

require 'benchmark'
require 'test/unit'

module SafeTranspose
  refine Array do
    def a
      max_length = max_by(&:size).size
      map { |value| Array.new(max_length) { |i| value[i] || '' } }.transpose
    end

    def b
      max_length = max_by(&:size).size
      map { |m| m.fill('', m.size, max_length - m.size) }.transpose
    end

    # def c
    #   # 先頭要素が最長である必要があるので却下
    #   self[0].zip(*self[1..-1])
    # end

    def d
      max_length = max_by(&:size).size
      map { |e| e.values_at(0...max_length) }.transpose
    end

    def e
      max_length = max_by(&:size).size
      Array.new(max_length) { |i| map { |e| e[i] } }
    end

    def f
      result = []
      max_size = max_by(&:size).size
      max_size.times do |i|
        result[i] = Array.new(first.size)
        each_with_index { |r, j| result[i][j] = r[i] }
      end
      result
    end
  end
end

using SafeTranspose

array = []

90000.times do
  array.push((1..rand(10)).to_a)
end

Benchmark.bm 10 do |r|
  ('a'..'f').to_a.each do |m|
    next if m == 'c'
    r.report m do
      array.send(m)
    end
  end
end

class SafeTransposeTest < Test::Unit::TestCase
  using SafeTranspose

  @@array = []

  10.times do
    @@array.push((1..rand(10)).to_a)
  end

  ('a'..'f').each do |m|
    next if m == 'c'
    define_method("test_#{m}") do
      assert_equal @@array.a, @@array.send(m)
    end
  end
end

結果

                 user     system      total        real
a            0.180000   0.020000   0.200000 (  0.203185)
b            0.090000   0.000000   0.090000 (  0.093895)
d            0.110000   0.010000   0.120000 (  0.116067)
e            0.120000   0.000000   0.120000 (  0.124450)
f            0.190000   0.010000   0.200000 (  0.195936)
Loaded suite safe_transpose_test
Started
.....

Finished in 0.001421 seconds.
---------------------------------------------------------------------------------------------------------------------------------------
5 tests, 5 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
---------------------------------------------------------------------------------------------------------------------------------------
3518.65 tests/s, 3518.65 assertions/s