Making hash key from arrays

Hi All,

I’ve two arrays,

keys = [300,300,301,301,301,302,302]

values = [1, 2, 1, 3, 4, 3, 4]

both the arrays have equal size.

I need to create a hask

hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

Could any one please put the ruby code for this.

Cheers
A

On Mon, 7 Feb 2011 20:47:45 +0900, Arihan S. wrote:

I need to create a hask

hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

Could any one please put the ruby code for this.

Cheers
A

hsh = Hash.new{|h,k| h[k]=[]}
keys.zip(values).each{|k,v| hsh[k] << v}

Thanks for this but I am getting like

[[300, 1], [300, 2], [301, 1], [301, 3], [301, 4], [302, 3], [302, 4]]

but I actually need like

hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

any help

its working ok. my aplogies cheers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Feb 7, 2011, at 7:12 AM, Arihan S. wrote:

Thanks for this but I am getting like

[[300, 1], [300, 2], [301, 1], [301, 3], [301, 4], [302, 3], [302, 4]]

but I actually need like

hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

any help

In ruby 1.9’s irb:

ratdog:~ mike$ irb

keys = [300,300,301,301,301,302,302]
=> [300, 300, 301, 301, 301, 302, 302]

values = [1, 2, 1, 3, 4, 3, 4]
=> [1, 2, 1, 3, 4, 3, 4]

hsh = Hash.new{ |h, k| h[k] = [] }
=> {}

keys.zip(values) { |k, v| hsh[k] << v }
=> nil

hsh
=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

Mike


Mike S. [email protected]
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (Darwin)

iEYEARECAAYFAk1P434ACgkQnsTBwAWZE9q80gCdEdw+bHUgGBNYGKYt4VmHg72R
cI4An0go3pXoDATGibvDOPQO5QdNCRa/
=5+ET
-----END PGP SIGNATURE-----

On Mon, 7 Feb 2011 21:28:21 +0900, Robert K. wrote:

=> {}
Btw, #zip without #each is more efficient:
robert
Thanks, I never knew #zip took a block argument before.

On Mon, Feb 7, 2011 at 1:12 PM, Arihan S. [email protected]
wrote:

Thanks for this but I am getting like

[[300, 1], [300, 2], [301, 1], [301, 3], [301, 4], [302, 3], [302, 4]]

???

irb(main):004:0> hsh = Hash.new{|h,k| h[k]=[]}
=> {}
irb(main):005:0> keys.zip(values).each{|k,v| hsh[k] << v}
=> [[300, 1], [300, 2], [301, 1], [301, 3], [301, 4], [302, 3], [302,
4]]
irb(main):006:0> hsh
=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

but I actually need like

hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

Btw, #zip without #each is more efficient:

irb(main):007:0> hsh = Hash.new{|h,k| h[k]=[]}
=> {}
irb(main):008:0> keys.zip(values) {|k,v| hsh[k] << v}
=> nil
irb(main):009:0> hsh
=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

Cheers

robert

On Mon, Feb 7, 2011 at 1:43 PM, Alex G.
[email protected] wrote:

Thanks, I never knew #zip took a block argument before.

IIRC that was introduced later. If my memory does not fail me
originally Array#zip only returned an Array and block handling (as
well as multiple Array arguments to Array#zip) were added later.

Kind regards

robert

On Mon, Feb 7, 2011 at 7:47 PM, Arihan S. [email protected]
wrote:

keys = [300,300,301,301,301,302,302]
values = [1, 2, 1, 3, 4, 3, 4]
hsh = {“300” =>[“1”,“2”],“301” => [“1”,“3”,“4”],“302”=>[“3”,“4”]}

just joining the fun here… an inject version

keys.zip(values).inject(Hash.new{|h,k|h[k]=[]}) {|hsh,(k,v)|
hsh.tap{|h|h[k] << v}}
#=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

or

keys.zip(values).inject2(Hash.new{|h,k|h[k]=[]}) {|h,(k,v)| h[k] << v}
#=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

best regards -botp

botp wrote in post #980085:

just joining the fun here… an inject version

keys.zip(values).inject(Hash.new{|h,k|h[k]=[]}) {|hsh,(k,v)|
hsh.tap{|h|h[k] << v}}
#=> {300=>[1, 2], 301=>[1, 3, 4], 302=>[3, 4]}

That’s a prime example of using inject purely for obfuscation.

The principal property of inject is that the value which is the output
of one iteration is fed in as in input to the next iteration. You’re not
using that property here, because you’re mutating the same object each
time. In that case, it’s just a complicated way of saying ‘each’. You
may as well just write:

h = Hash.new { |h,k| h[k] = [] }
keys.zip(values).each { |k,v| h[k] << v }
h

Furthermore, if you insist on using #tap, at least do it on the outside
where it belongs in this case:

Hash.new { |h,k| h[k] = [] }.tap do |hsh|
keys.zip(values).each { |k,v| hsh[k] << v }
end

Now, if you wanted to do this in a functional way using inject, then you
would mutate nothing and instead build a new Hash object in each
iteration:

keys.zip(values).inject({}) do |hsh,(k,v)|
if hsh.has_key?(k)
hsh.merge(k=>hsh[k]+[v])
else
hsh.merge(k=>[v])
end
end

That, in my opinion, is the correct way to use inject here - and it’s
reasonably clear when written that way too. The Ruby runtime will end up
doing a lot of hash copying though.

Regards,

Brian.

on Wed, Feb 9, 2011 at 4:01 AM, Brian C. [email protected]
wrote:

… That, in my opinion, is the correct way to use inject here…

i agree that we disagree :slight_smile:

best regards -botp