Hatena::Grouprubyist

trotrの日記

2008-07-13

module Enumerable
  def my_zip(*args)
    if block_given?
      enum = args.map{ |e| e.enum_for(:each)}
      self.each do |e|
        yield([e, *enum.map{ |e| e.next rescue nil }])
      end
    else
      (0...self.length).inject([]) do |re, i|
        re.tap{ re[i] = [self[i], *args.map{ |e| e[i]}]}
      end
    end
  end
end

[1,2,3,4,5].my_zip([3,4,5]){ |e| p e}
# [1, 3]
# [2, 4]
# [3, 5]
# [4, nil]
# [5, 3]
p [1,2,3].my_zip([3,4])
# [[1, 3], [2, 4], [3, nil]]

"[1,2,3].zip([1,10,100]).map{|x,y| x * y }"と同じような処理をするときには、zipArrayを生成しないようにblockを使った方がいいかも.

**こんな感じで、

>|ruby|

[1,2,3].enum_for(:zip, [1,10,100]).map{|x,y| x * y }

||<

**速度

速度はあまり変わらない。

require 'benchmark'
Benchmark.bmbm do |x|
  n = 1000000
  a  = Array.new(n,3)
  b = Array.new(n,10)
  x.report("zip -> map"){ a.zip(b).map{ |x,y| x*y}}
  x.report("to_enum(:zip, *args"){ a.to_enum(:zip, b).map{ |x,y| x * y}}
end
=begin
Rehearsal -------------------------------------------------------
zip -> map            1.160000   0.050000   1.210000 (  1.229003)
to_enum(:zip, *args   1.370000   0.020000   1.390000 (  1.404765)
---------------------------------------------- total: 2.600000sec

追記

nの値を大きくしてみたらかなり変わった。

n = 10000000でやってみると

Arrayを生成してから計算。

Rehearsal ----------------------------------------------
zip -> map  14.370000   0.700000  15.070000 ( 15.180819)
------------------------------------ total: 15.070000sec

                 user     system      total        real
zip -> map  12.820000   0.440000  13.260000 ( 13.406720)
||<	
メモリの使用量は70%位に
Arrayを生成しないでブロックで
>||
Rehearsal -------------------------------------------------------
to_enum(:zip, *args 165.000000   0.570000 165.570000 (166.855531)
-------------------------------------------- total: 165.570000sec

                          user     system      total        real
to_enum(:zip, *args 163.970000   0.570000 164.540000 (165.858670)

メモリの使用量は15%程度。でも、速度は10分の1位。

ゲスト



トラックバック - http://rubyist.g.hatena.ne.jp/trotr/20080713