From: Paul Harrington Date: 2010-09-09T05:22:01+09:00 Subject: Re: Problem with Hash of Arrays Fearless Fool wrote: > This is a long-inactive thread, but it glosses over an important gotcha > that nobody has mentioned. > > As mentioned above, the sexy ruby-esque way to make a hash of arrays is > to use a block initializer for Hash.new: > >>> h = Hash.new{|hash, key| hash[key] = []} > => {} > > This allows you to push items onto any slot of the hash without first > checking to see if it's nil: > >>> h[:first] << "yum!" > => ["yum!"] >>> h[:first] << "tastes like chicken" > => ["yum!", "tastes like chicken"] > > But here's the gotcha: If you later test for a non-empty slot with > h[], h will automatically create an empty array whether you > intended to or not. Consider: > > process(h[:second]) if h[:second] > > Even though we never pushed anything onto h[:second], process() WILL get > called (and the hash will grow by one element), since the test > h[:second] automagically creates an empty array. This may not be a > problem if you use h entirely within your own code, but could be > surprising behavior -- to you or to some other user -- and lead to > elusive bugs. (As I discovered...) > > MORAL: A better idiom for pushing items onto a hash of arrays is: > >>> h = Hash.new >>> (h[:first] ||= []) << "yum!" > > ... since this avoids any unexpected behavior with the hash later on. > > - ff This here is why you learn the core library. irb(main):025:0> h = Hash.new {|h, k| h[k] = []} => {} irb(main):026:0> h[:rocks].push "cliff" => ["cliff"] irb(main):027:0> h[:rocks] => ["cliff"] irb(main):028:0> h.has_key? :face => false -- Posted via http://www.ruby-forum.com/.