Your test doesn't prove higher memory usage for the inject
version. The problem with the transpose approach is that you
need an additional copy of the complete hash in mem which is
not needed for inject. However, inject version is likely to
cause more GC because of all the two element arrays created.
You could retest this:
keys, vals = [], [] hash.each {|k,v| keys << k; vals << v}
This should be the most efficient approach - memory and
performance wise.
Hihi... ;]
Remember, both to_a and transpose are implemented in C.
Yes, right. Still some remarks
- by not using GC you will see the memory used in total but this does
not give a realistic result because it omits GC times and it does make a
difference whether you only allocate small chunks and release them again
or whether you need a copy of the whole data structure in memory, so
- memory wise approach "each" is the most efficient
- "traditional" is not semantically identical to the other approaches
because it's not guaranteed that both are in the same order
Some more figures:
08:58:59 [Temp]: ./test2.rb
Rehearsal -----------------------------------------------
traditional 1.375000 0.000000 1.375000 ( 1.375000)
transpose 11.203000 0.000000 11.203000 ( 11.203000)
inject 45.188000 0.000000 45.188000 ( 45.187000)
each 20.140000 0.000000 20.140000 ( 20.157000)
------------------------------------- total: 77.906000sec
user system total real
traditional 1.391000 0.000000 1.391000 ( 1.390000)
transpose 11.281000 0.000000 11.281000 ( 11.282000)
inject 45.219000 0.000000 45.219000 ( 45.234000)
each 19.813000 0.000000 19.813000 ( 19.812000)
Cheers
robert
#!/usr/bin/env ruby
require 'benchmark'
REPEAT = 1_00_000
REP = 10_000
hash = {}
1000.times do |n|
hash[n] = n*n
end
Benchmark.bmbm do |bm|
bm.report "traditional" do
REP.times do
keys = hash.keys
values = hash.values
end
end
bm.report "transpose" do
REP.times do
keys, values = hash.to_a.transpose
end
end
bm.report "inject" do
REP.times do
keys, values = hash.inject([[],[]]){|(ks,vs),(k,v)| [ks << k, vs << v]}
end
end
bm.report "each" do
REP.times do
keys, vals = [], []
hash.each {|k,v| keys << k; vals << v}
end
end
end