From: Robert Dober Date: 2007-03-14T15:14:03+09:00 Subject: Re: non-destructive merging of hashes in array On 3/13/07, Trans wrote: > On Mar 13, 8:40 am, "Robert Dober" wrote: > > On 3/13/07, Trans wrote: > > > > > > > > > On Mar 12, 10:01 pm, "Giles Bowkett" wrote: > > > > Hi, I have an array of hashes. The keys in the hashes represent the same things. > > > > > > eg: > > > > > > h1 = {:rabbits => 5} > > > > h2 = {:rabbits => 10} > > > > > > bunnies = [h1, h2] > > > > > > I want to end up with this: > > > > > > {:rabbits => 15} > > > > > > It's a trivial task, but what's the quickest way to get there? I'm > > > > certain it can be done on one line. > > > > > > I know there's a Hash#update, but it appears that it would just > > > > replace the 10 with 5, or vice versa, rather than adding them up. > > > > > > This works, but it seems clunky: > > > > > > hashes.each do |h| > > > > h.each do |k, v| > > > > if new_hash[k] > > > > new_hash[k] += v > > > > else > > > > new_hash[k] = v > > > > end > > > > end > > > > end > > > > > > It can be crammed all onto one line, too, but there must be a nicer way. > > > > > (SORRY IF THIS GETS POSTED TWICE) > > > > > The inject/merge solutions are good, but they are one trick ponies. > > > How about something like: > > > > > OpenCollection[h1, h2].rabbits.sum > > > > > It shouldn't be too hard to write: > > > > > require 'ostruct' > > > > > class OpenCollection > > > class << self ; alias :[] :new ; end > > > def initialize(*hashes) > > > @opens = hashes.collect { |h| OpenStruct.new(h) } > > > end > > > > > def method_missing(sym, *args) > > > @opens.collect{ |o| o.send(sym) } > > > end > > > end > > > > > Actually, I'd use Facets OpenObject instead OpenStruct myself, but > > > that's just me. You'll also need: > > > > > require 'facets/core/enumerable/sum' > > > > > For fun, here's a one line version (more or less): > > > > > require 'facets/more/functor' > > > > > oc = Functor.new([h1,h2]){|s,m| m.map{|h| h[s]}} > > > > > oc.rabbits.sum > > > > > T. > > > > Tom Facet is a great thing and I do not fail to point to it regulary. > > But sometimes I feel we have to flex our muscles in pure Ruby before > > we shall use libraries, even excellent ones like Facets, just to > > understand everything a little better. > > > > This all does not mean that your post is not very valuable, I just > > want to warn from the "Pull In A Library before Do Some Thinking" > > approach. > > > > i fear that this approach hurts the user as much as the library. > > I understand what youre saying --and I waited on posting this until > others gave solutions. Though in this particular case I think there's > some pretty good meat here, ie. the OpenCollection class I literally > just made up on the spot. Of course that still leaves Enumerable#sum, > but that's rather straight forward: a.inject(0){|s,n| s+=n;s}. > > The Functor was just a little playful plug. If you've ever seen the > functor code you know it's a generalization of what the OpenCollection > class is doing. I actually would like to see Functor included in > Ruby's standard lib. But I haven't been able to convince Matz of it's > usefulness. So I try to publicly use it when ever I get the chance. > > HTH, > T. > > > OMG was I too rude, maybe? Probably just to stupid to really understand your mail :( The good thing is though that I understand now what you wanted to tell us. And I am one of the greatest fans of magic dot. Thx and sorry. Robert -- You see things; and you say Why? But I dream things that never were; and I say Why not? -- George Bernard Shaw