An hash of arrays, how to use?

Hello everybody!

I have a problem with an Hash of Arrays.

ruby-1.9.2-p136 :001 > x = Hash.new Array.new => {} ruby-1.9.2-p136 :002 > x["test"] << "test" => ["test"] ruby-1.9.2-p136 :003 > x => {} ruby-1.9.2-p136 :004 > x.keys => ruby-1.9.2-p136 :005 > x["test"] => ["test"] ruby-1.9.2-p136 :006 >

Why is keys empty?

What I am trying to do is build a hash of arrays from an XML file:

      b = Hash.new(Array.new)       h = XmlSimple.xml_in self.raw

      h["data"][0]["bank"][0]["item"].each do |item|         b[item["cat"]] << item["name"]       end

This is the code, but b has like the test in irb no keys, or seems to be empty, unless you dont know the key i advance, but that is impossible, since the item["cat"] is dynamic and it is known of 10 categories at the moment, but it is also known that the number of categories will go up in the future, so I want to do it future-proof already today :smiley:

Thank you in Advance Norbert

because you've never actually done x["test"]= ... (all you're doing is modifying the hash's default value)

Fred

OK, now I tried the following

      b = Hash.new(Array.new)       h = XmlSimple.xml_in self.raw

      h["data"][0]["bank"][0]["item"].each do |item|         if b.key? item["cat"]           b[item["cat"]] = item         else           b[item["cat"]] << item         end       end

      pp b.keys

but b.keys is still empty...

OK, now I tried the following

 b = Hash\.new\(Array\.new\)
 h = XmlSimple\.xml\_in self\.raw

 h\[&quot;data&quot;\]\[0\]\[&quot;bank&quot;\]\[0\]\[&quot;item&quot;\]\.each do |item|

delete line> if b.key? item["cat"] add line> if !b.key? item["cat"]

     b\[item\[&quot;cat&quot;\]\] = item
   else
     b\[item\[&quot;cat&quot;\]\] &lt;&lt; item
   end
 end

 pp b\.keys

call me stupid... But with above marked change it works as I want it to behave :smiley:

Thanks for the help!

Norbert

try this,

b = Hash.new {|h,k| h[k]=} h = XmlSimple.xml_in self.raw

h["data"][0]["bank"][0]["item"].each do |item|   b[item["cat"]] << item end

best regards -botp

>> Why is keys empty?

> because you've never actually done x["test"]= ... > (all you're doing is modifying the hash's default value)

OK, now I tried the following

  b = Hash\.new\(Array\.new\)
  h = XmlSimple\.xml\_in self\.raw

  h\[&quot;data&quot;\]\[0\]\[&quot;bank&quot;\]\[0\]\[&quot;item&quot;\]\.each do |item|
    if b\.key? item\[&quot;cat&quot;\]
      b\[item\[&quot;cat&quot;\]\] = item
    else
      b\[item\[&quot;cat&quot;\]\] &lt;&lt; item

You're still essentially committing the same error - you're only setting b[item['cat'] if there is already an entry for b[item['cat']] Did you really mean to use a hash with a single array as its default value? (The default value stuff doesn't seem to be helping you at all, just muddying the waters

Fred

As I mentioned above, my version did it after I introduced "if !b.key? [...]". But I will test the code that botp gave me too, seems to be more DRY :smiley:

Hi Norbert:

An idiom that I use frequently is:

h = {} (h[key] ||= ) << item

which essentially says "if hash h[key] is nil, create an empty array for that key. then push item onto the array. for example:

h = {}

=> {}

(h["cats"] ||= ) << "Jellicle"

=> ["Jellicle"]

(h["cats"] ||= ) << "Mr. Mistoffelees"

=> ["Jellicle", "Mr. Mistoffelees"]

Is that what you were looking for?

- ff