From: Josh Cheek Date: 2009-10-02T06:11:56+09:00 Subject: Re: how do you do this --000e0cd15226b671f90474e618d5 Content-Type: text/plain; charset=ISO-8859-1 On Thu, Oct 1, 2009 at 2:21 PM, Ryan Davis wrote: > Well... inject ALWAYS loses, but fanboys sure seems to like it for no good > reason. > > By using better names and the right tool for the job, this becomes a LOT > more readable, maintanable, and faster all in one fell swoop: > > by_length = Hash.new { |h,k| h[k] = [] } > strings.each do |string| > by_length[string.length] << string > end > by_length.values # I think this part is a mistake, but I wanted to match > > I think the readability is more important than speed by a long shot... But > just in case you're not convinced, check out the benchmarks: > > % ./blah.rb 10000 > # of iterations = 10000 > user system total real > null_time 0.000000 0.000000 0.000000 ( 0.001370) > mine 7.790000 0.050000 7.840000 ( 7.869737) > yours-inject 15.170000 0.050000 15.220000 ( 15.554334) > yours-each 11.850000 0.100000 11.950000 ( 12.013553) > > inject is twice as slow as mine. stop using it. > I generalized yours, and made the returned groups sorted by the results from the call. In this more comparable situation, inject is about 11% slower, not twice as slow. Inject Test Rehearsal -------------------------------------------------- Without Inject 14.160000 0.100000 14.260000 ( 14.364824) With Inject 15.950000 0.120000 16.070000 ( 16.258609) ---------------------------------------- total: 30.330000sec user system total real Without Inject 14.200000 0.110000 14.310000 ( 14.553592) With Inject 16.000000 0.120000 16.120000 ( 16.422186) Inject is about 11.38% slower Here is the code: #!/usr/bin/env ruby require 'benchmark' class Symbol def to_proc Proc.new{|obj| obj.send self } # give 1.9ish syntax end end module Enumerable def group_by_without_inject( &get_key ) groups = Hash.new { |h,k| h[k] = Array.new } each do |obj| groups[ get_key[obj] ] << obj end groups.keys.sort!.map!{|key| groups[key] } end def group_by_with_inject( &get_key ) groups = inject Hash.new{ |h,k| h[k] = Array.new } do |groups,obj| groups[ get_key[obj] ] << obj groups end groups.keys.sort!.map!{|key| groups[key] } end end puts "Inject Test" benchmarks = Benchmark.bmbm do|b| x = ["abc","abcde","def","xyzwj"] b.report("Without Inject") do 500_000.times{ x.group_by_without_inject &:length } end b.report("With Inject") do 500_000.times{ x.group_by_with_inject &:length } end end benchmarks.map!{|b| b.real } percent_slower = sprintf( "%.2f" , 100 - 100 * benchmarks.first / benchmarks.last ) puts '' , "Inject is about #{ percent_slower }% slower" --000e0cd15226b671f90474e618d5--