From: Paul Brannan Date: 2008-03-13T00:35:36+09:00 Subject: Re: duplicating characters in a string Some things to keep in mind: - captures can be slow, so if you can avoid them, you can get better performance - looping using "for" is usually faster than using "each { ... }", because it doesn't have to create a new scope every time the block is called Three alternative solutions added given the above (my computer is slower than yours, so I reduced the number of iterations too). Interesting that I was able to write an enumerator class in ruby that was faster than the builtin enumerator class (which is written in C). Also interesting is how much slower the enumerator solution is on YARV: require 'benchmark' require 'enumerator' class EachByteEnumerator def initialize(obj) @obj = obj end def each(&block) @obj.each_byte(&block) end end Benchmark.bmbm do |b| s = "abc" * 100_000 re = /(.)/ b.report("s.gsub(re) {|x| x*2}") do s.gsub(re) {|x| x*2} end b.report("s.gsub(re, '\\1\\1')") do s.gsub(re, '\1\1') end b.report("s.gsub(/./, '\\0\\0')") do s.gsub(/./, '\0\0') end b.report("7stud1") do new_str = "" s.each_byte do |byte| 2.times do new_str << byte end end end b.report("7stud2") do new_str = "" s.each_byte do |byte| new_str << byte << byte end end b.report("7stud_enum") do new_str = "" o = s.to_enum(:each_byte) for byte in o do new_str << byte << byte end end b.report("7stud_enum2") do new_str = "" o = EachByteEnumerator.new(s) for byte in o do new_str << byte << byte end end end [pbrannan@zaphod tmp]$ ruby test.rb Rehearsal -------------------------------------------------------- s.gsub(re) {|x| x*2} 2.410000 0.010000 2.420000 ( 2.431675) s.gsub(re, '\1\1') 0.900000 0.140000 1.040000 ( 1.035942) s.gsub(/./, '\0\0') 0.840000 0.070000 0.910000 ( 0.919175) 7stud1 1.430000 0.000000 1.430000 ( 1.430979) 7stud2 0.580000 0.010000 0.590000 ( 0.585925) 7stud_enum 0.820000 0.010000 0.830000 ( 0.837720) 7stud_enum2 0.510000 0.000000 0.510000 ( 0.511776) ----------------------------------------------- total: 7.730000sec user system total real s.gsub(re) {|x| x*2} 2.450000 0.000000 2.450000 ( 2.455824) s.gsub(re, '\1\1') 0.860000 0.010000 0.870000 ( 0.861705) s.gsub(/./, '\0\0') 0.820000 0.000000 0.820000 ( 0.818279) 7stud1 1.460000 0.010000 1.470000 ( 1.483312) 7stud2 0.590000 0.000000 0.590000 ( 0.589141) 7stud_enum 0.820000 0.000000 0.820000 ( 0.817231) 7stud_enum2 0.520000 0.000000 0.520000 ( 0.514009) [pbrannan@zaphod tmp]$ ruby1.9 test.rb Rehearsal -------------------------------------------------------- s.gsub(re) {|x| x*2} 2.880000 0.030000 2.910000 ( 2.961747) s.gsub(re, '\1\1') 1.850000 0.120000 1.970000 ( 1.972712) s.gsub(/./, '\0\0') 1.770000 0.040000 1.810000 ( 1.815295) 7stud1 1.040000 0.000000 1.040000 ( 1.056692) 7stud2 0.640000 0.000000 0.640000 ( 0.660844) 7stud_enum 1.710000 0.080000 1.790000 ( 1.786316) 7stud_enum2 1.640000 0.120000 1.760000 ( 1.770983) ---------------------------------------------- total: 11.920000sec user system total real s.gsub(re) {|x| x*2} 2.950000 0.030000 2.980000 ( 2.999795) s.gsub(re, '\1\1') 1.910000 0.030000 1.940000 ( 1.938242) s.gsub(/./, '\0\0') 1.760000 0.030000 1.790000 ( 1.811339) 7stud1 1.040000 0.000000 1.040000 ( 1.055916) 7stud2 0.650000 0.030000 0.680000 ( 0.685329) 7stud_enum 1.520000 0.120000 1.640000 ( 1.661215) 7stud_enum2 1.450000 0.120000 1.570000 ( 1.590461) [pbrannan@zaphod tmp]$ ruby1.9 -v ruby 1.9.0 (2008-01-24 revision 0) [i686-linux]