Problem with ruby19's Hash behavior

see the following codes pls, I wonder if this’s a intent or a bug. For
me the first line sounds better having same result with the later line

[1].inject(Hash.new {[]}){ |result, i| result[:mem] << i; result }
=> {}

[1].inject(Hash.new {[]}){ |result, i| result[:mem] <<= i; result }
=> {:mem=>[1]}

P.S. coding with ruby 1.9.2p180 atm

Hi Aaron

2011/4/25 Aaron [email protected]:

see the following codes pls, I wonder if this’s a intent or a bug. For me the
first line sounds better having same result with the later line

[1].inject(Hash.new {[]}){ |result, i| result[:mem] << i; result }
=> {}
[1].inject(Hash.new {[]}){ |result, i| result[:mem] <<= i; result }
=> {:mem=>[1]}

It’s the expected behaviour. See
class Hash - RDoc Documentation.

“If a block is specified, it will be called with the hash object and
the key, and should return the default value. It is the block‘s
responsibility to store the value in the hash if required.”

[1].inject(Hash.new {|h,k| h[k] = Array.new}){ |result, i|
result[:mem] << i; result }
=> {:mem=>[1]}

Hi,

I still cannot understand.

In the first example, result[:mem] should be [ ] before “result[:mem] <<
i” is
executed. Afterwards it should be [1], and the return value should be
{:mem =>
[1]}.

In the second example, what does “<<=” stand for?

Roy

@Roy

<<= should behave like +=, -= etc

Thanks a lot :wink:

kind of clear now, so my code’s problem is Hash.new{[]} didn’t store the
array object into the Hash

On Apr 25, 2011, at 8:25 AM, Aaron wrote:

Thanks a lot :wink:

kind of clear now, so my code’s problem is Hash.new{[]} didn’t store
the array object into the Hash

If you want the value stored, you need to do it yourself:

[1].inject(
Hash.new{|h,k|h[k]=[]}
){ |result, i| result[:mem] << i;
result }
=> {:mem=>[1]}

-Rob

Rob B.
[email protected] http://AgileConsultingLLC.com/
[email protected] http://GaslightSoftware.com/

@Rob thanks

I thought Hash.new{[]} was shortcut for Hash.new{|h,k|h[k]=[]}

On Apr 26, 2011, at 4:10 AM, Aaron wrote:

@Rob thanks

I thought Hash.new{[]} was shortcut for Hash.new{|h,k|h[k]=[]}

The block form is executed when the requested key does not exist. It
makes each call a new array (which is then thrown away).n

irb> answer = [1,4,9].inject(Hash.new {[]}){ |result, i| result[:mem]
<< i; result }
=> {}
irb> answer[:mem]
=> []
irb> answer[:foo]
=> []

The non-block form makes a single array the default for all keys. The
resulting hash still has no entries, but if you ask for any key that
doesn’t exist, you’ll get the (one) default value back. That default
value is a true object that is modified by the << each time the inject
block is executed.

irb> answer = [1,4,9].inject(Hash.new([])){ |result, i| result[:mem]
<< i; result }
=> {}
irb> answer[:mem]
=> [1, 4, 9]
irb> answer[:foo]
=> [1, 4, 9]

Even though your question was for ruby 1.9, the same behavior is found
in 1.8.

-Rob

Rob B.
[email protected] http://AgileConsultingLLC.com/
[email protected] http://GaslightSoftware.com/