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

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]}

···

2011/4/25 Aaron <aaron2ti@gmail.com>:

--
Roger Braun
rbraun.net | humoralpathologie.de

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

···

On Mon, Apr 25, 2011 at 08:50:13PM +0900, Roger Braun wrote:

Hi Aaron

2011/4/25 Aaron <aaron2ti@gmail.com>:
> 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]}

--
Roger Braun
rbraun.net | humoralpathologie.de

--

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

@Roy

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

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 Biedenharn
Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/
rab@GaslightSoftware.com http://GaslightSoftware.com/

···

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

@Rob thanks

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

@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

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

<< i; result }
=> {}

answer[:mem]

=>

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.

answer = [1,4,9].inject(Hash.new()){ |result, i| result[:mem]

<< i; result }
=> {}

answer[:mem]

=> [1, 4, 9]

answer[:foo]

=> [1, 4, 9]

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

-Rob

Rob Biedenharn
Rob@AgileConsultingLLC.com http://AgileConsultingLLC.com/
rab@GaslightSoftware.com http://GaslightSoftware.com/

···

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