Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > hash.keys and hash.values

Reply
Thread Tools

hash.keys and hash.values

 
 
Chad Perrin
Guest
Posts: n/a
 
      08-14-2006
On Tue, Aug 15, 2006 at 12:06:51AM +0900, Mage wrote:
> Chad Perrin wrote:
> >
> >I suspect people don't even get as far as taking it for granted, since
> >they probably tend to access one from the other in almost all cases.
> >

> On the second week of my Ruby "experience" I found myself writing a
> method (for a very basic db layer) where hash.keys and hash.values could
> come in play.
> So I think it's a natural need. After a short Google session I found
> others dealing with this, most of them assumed that they have same order.


I stand corrected.


>
> Based on the answers of this thread I believe they are, however until it
> becomes documented I will use hash.to_a.transpose in production environment.


That's probably an excellent policy.

--
CCD CopyWrite Chad Perrin [ http://ccd.apotheon.org ]
"It's just incredible that a trillion-synapse computer could actually
spend Saturday afternoon watching a football game." - Marvin Minsky

 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      08-14-2006
Erik Veenstra wrote:
>> Here's another solution - maybe it's even more efficient as
>> it doesn't need the transposing:

>
> Well, a quick benchmark... No, it isn't more efficient. Neither
> time-wise, nor memory-wise.


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.

Kind regards

robert
 
Reply With Quote
 
 
 
 
Erik Veenstra
Guest
Posts: n/a
 
      08-14-2006
> 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.

gegroet,
Erik V. - http://www.erikveen.dds.nl/

PS: The circumstances are a bit different, compared to my
previous post. Different environment, different numbers.

----------------------------------------------------------------

$ cat test.rb
require "ev/ruby"

GC.disable

hash = {}

1000.times do |n|
hash[n] = n*n
end

case ARGV.shift
when "traditional"
bm do
1000.times do
keys = hash.keys
values = hash.values
end
end
when "transpose"
bm do
1000.times do
keys, values = hash.to_a.transpose
end
end
when "inject"
bm do
1000.times do
keys, values = hash.inject([[],[]]){|(ks,vs),(k,v)| [ks <<
k, vs << v]}
end
end
when "inject2"
bm do
1000.times do
keys, vals = [], []
hash.each {|k,v| keys << k; vals << v}
end
end
else
raise "uh?"
end

puts meminfo

$ ruby test.rb traditional
VmSize: 14296 kB
CPU ELAPSED COUNT CPU/COUNT LABEL
0.300000 0.310413 1 0.300000 "test.rb:13"

$ ruby test.rb transpose
VmSize: 58280 kB
CPU ELAPSED COUNT CPU/COUNT LABEL
0.760000 0.861536 1 0.760000 "test.rb:20"

$ ruby test.rb inject
VmSize: 146676 kB
CPU ELAPSED COUNT CPU/COUNT LABEL
3.190000 3.331201 1 3.190000 "test.rb:26"

$ ruby test.rb inject2
VmSize: 55244 kB
CPU ELAPSED COUNT CPU/COUNT LABEL
1.690000 1.819222 1 1.690000 "test.rb:32"

----------------------------------------------------------------


 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      08-15-2006
On 14.08.2006 21:01, Erik Veenstra wrote:
>> 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

 
Reply With Quote
 
Mage
Guest
Posts: n/a
 
      08-15-2006
Well, I like Ruby's community.

Thank you all for your time.

Mage



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
if and and vs if and,and titi VHDL 4 03-11-2007 05:23 AM



Advertisments