Clean nice way (hash)

I did eliminate some Hashes, those created for each iteration inject(), so I feel it's wrong to say it didn't help. You are right about the parameter Hashes though.

I do feel nitpicking something like this is squarely in the domain of premature optimization though. It's GC's job to lose sleep over the objects I create, not mine. I don't need to get involved until it looks like GC is getting behind. Those are my feelings on the matter.

James Edward Gray II

···

On Jul 16, 2007, at 12:10 PM, Robert Klemme wrote:

On 16.07.2007 17:03, James Edward Gray II wrote:

On Jul 16, 2007, at 9:36 AM, Robert Klemme wrote:

2007/7/16, Chris Carter <cdcarter@gmail.com>:

On 7/16/07, James Edward Gray II <james@grayproductions.net> wrote:
> On Jul 16, 2007, at 5:58 AM, hemant wrote:
>
> > a.inject({}) {|mem,(key,value)| mem[key] = {'name' => value}; mem }
>
> I would write that as:
>
> a.inject(Hash.new) { |h, (k, v)| h.merge(k => v) }
>
> James Edward Gray II
>

But that doesn't yield what he wanted... You could do
a.inject(Hash.new){|h,(k,v)| h.merge(k => { 'name' => value})}

Still it's inefficient because of all the small Hashes that are thrown
away immediately. The solution provided by hemant is better although
not as elegant.

If that bothers you, change merge() to merge!().

... which doesn't help because it does not avoid all those one pair hashes. :slight_smile:

Ahh, ok, till now I thought {} calls Hash[] but I didn't know what
literals really are...

Thanks
Florian

Ok, I think GC is the main problem in my setup :smiley:

I tried benchmark and #each behaves much better than #update. #update
produces too much overhead... :frowning:

The source below can kill your memory since I disabled the GC and only
call it manually...

Regards
Florian

require 'benchmark'

Benchmark.bm do |x|
  GC.disable

  tests = [
    Proc.new do
      hash = ('aaaa'..'zzzz').inject Hash.new do |mem, value|
        mem[value] = value
        mem
      end
      block = proc { |key, o_val, n_val| {:name => o_val} }
      x.report('Hash#update') { hash.update(hash, &block) }
    end ] + [
    Proc.new do
      hash = ('aaaa'..'zzzz').inject Hash.new do |mem, value|
        mem[value] = value
        mem
      end
      block = proc { |key, value| hash[key] = {:name => value} }
      x.report('Hash#each') { hash.each(&block) }
    end
  ]

  12.times do |iteration|
    if (iteration % 3).zero?
      GC.start
      sleep 3
    else
      tests[ rand(2) ].call
    end
  end

end
GC.enable
sleep 5

>
> > a.inject({}) {|mem,(key,value)| mem[key] = {'name' => value}; mem }
>
> I would write that as:
>
> a.inject(Hash.new) { |h, (k, v)| h.merge(k => v) }
>
> James Edward Gray II
>

But that doesn't yield what he wanted... You could do
a.inject(Hash.new){|h,(k,v)| h.merge(k => { 'name' => value})}

Still it's inefficient because of all the small Hashes that are thrown
away immediately. The solution provided by hemant is better although
not as elegant.

If that bothers you, change merge() to merge!().

... which doesn't help because it does not avoid all those one pair hashes. :slight_smile:

I did eliminate some Hashes, those created for each iteration inject(), so I feel it's wrong to say it didn't help. You are right about the parameter Hashes though.

Those were the ones I referred to originally. And yes, "did not help" was only partly true. :wink:

I do feel nitpicking something like this is squarely in the domain of premature optimization though. It's GC's job to lose sleep over the objects I create, not mine. I don't need to get involved until it looks like GC is getting behind. Those are my feelings on the matter.

I think I understand your point and as a geneal statement I even do agree. However, another general statement that I'd add to the mix is "do not make superfluous work if you can avoid it easily". For me this is such a case: we just get a slightly more elegant solution by using #merge because we do not need to mention the Hash to make #inject happy, but we force the machine to do a lot of extra work (how much remains to be measured). It's not exactly a comparable case but if I have a tree where data is stored with a particular order I would not do a full traversal when searching for a specific element (O(n)); instead I'd use an algorith that's aware of the tree structure and the ordering (O(log(n))).

Kind regards

  robert

···

On 16.07.2007 20:15, James Edward Gray II wrote:

On Jul 16, 2007, at 12:10 PM, Robert Klemme wrote:

On 16.07.2007 17:03, James Edward Gray II wrote:

On Jul 16, 2007, at 9:36 AM, Robert Klemme wrote:

2007/7/16, Chris Carter <cdcarter@gmail.com>:

On 7/16/07, James Edward Gray II <james@grayproductions.net> wrote:
> On Jul 16, 2007, at 5:58 AM, hemant wrote: