Question

I use various versions of the code below to find a particular entry in an array of hashes and then return a different hash value or sub-array. This multi-level array/hash structures are common when importing XML using XMLSimple (e.g. I don't get to control how the data structure is organized).

This will result in an error anytime find fails to locate a result:

value = ary.find {|r| r["rail"][0] == lookup_rail}["id"][0]

This will work using tap but gets uglier with more and more subarrays and subhashes.

ary.find {|r| r["rail"][0] == lookup_rail}.tap do |f|
  value = f.nil? ? nil : (f["id"].nil? nil : f["id"][0])
end

Is there a way to not have the program error out if I reference a sub-array of a nil object (without adding to NilClass)?

Is there a way to check for the existence of the sub-sub-array entry and then perform any assignment operations?

Was it helpful?

Solution 2

In Ruby 2.0+, nil.to_h is { }; also, nil.to_a has been [ ] as long as I can remember. Of course, if h is a Hash then h.to_h is h and if a is an Array then a.to_a is a. You can use this to hide nils thusly:

value = ary.find {|r| r["rail"][0] == lookup_rail}.to_h["id"].to_a[0]

OTHER TIPS

How about using &&?

x = {"id" => ["train"]}
x && x["id"] && x["id"][0]
# => "train"

x = {"id" => nil}
x && x["id"] && x["id"][0]
# => nil

x = nil
x && x["id"] && x["id"][0]
# => nil

ary.find {|r| r["rail"][0] == lookup_rail}.tap do |f|
  value = f && f["id"] && f["id"][0]
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top