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
Thank you in Advance
Norbert
On Feb 11, 9:09pm, Norbert M. [email protected] wrote:
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?
because you’ve never actually done x[“test”]= …
(all you’re doing is modifying the hash’s default value)
Fred
2011/2/11 Frederick C. [email protected]:
On Feb 11, 9:09pm, Norbert M. [email protected] wrote:
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["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…
On Sat, Feb 12, 2011 at 9:25 AM, Norbert M.
[email protected] wrote:
end
pp b.keys
call me stupid… But with above marked change it works as I want it
to behave
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
On Feb 12, 12:47am, Norbert M. [email protected] wrote:
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
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
2011/2/12 Frederick C. [email protected]:
On Feb 12, 12:47am, Norbert M. [email protected] wrote:
2011/2/11 Frederick C. [email protected]:
just muddying the waters
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
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|
delete line> if b.key? item[“cat”]
add line> if !b.key? item[“cat”]
b[item[“cat”]] = item
else
b[item[“cat”]] << item
end
end
pp b.keys
call me stupid… But with above marked change it works as I want it
to behave
Thanks for the help!
Norbert
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?