ruby use array tvalues to index nested hash of hash
And then there's:
keys.inject(hash, :fetch)
or for earlier Ruby versions:
keys.inject(hash) {|h, k| h[k]}
If you did want to use recursion, a more Rubyesque approach would be:
def get_value(obj, keys)
keys.empty? ? obj : get_value(obj[keys[0]], keys[1..-1])
end
Access nested hash element specified by an array of keys
hash = { "a" => { "b" => 'foo' }}
array = ["a", "b"]
array.inject(hash,:fetch)
# => "foo"
array.inject(hash,:[])
# => "foo"
change value in hash using an array of keys in ruby
Use all but the last key to get the most deeply nested Hash, then assign normally using the last key.
keys[0...-1].inject(hash, :fetch)[keys.last] = value
Ruby doesn't have references so you can't reassign the value directly. Instead you have to reassign the object pointer, which means going up one level of nesting.
What is the most ruby-ish way of accessing nested hash values at arbitrary depths?
def val_for(hash, keys)
keys.reduce(hash) { |h, key| h[key] }
end
This will raise an exception if some intermediate key is not found. Note also that this is completely equivalent to keys.reduce(hash, :[])
, but this may very well confuse some readers, I'd use the block.
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
Ruby 2.3.0 introduced a new method called dig
on both Hash
and Array
that solves this problem entirely.
name = params.dig(:company, :owner, :name)
It returns nil
if the key is missing at any level.
If you are using a version of Ruby older than 2.3, you can use the ruby_dig gem or implement it yourself:
module RubyDig
def dig(key, *rest)
if value = (self[key] rescue nil)
if rest.empty?
value
elsif value.respond_to?(:dig)
value.dig(*rest)
end
end
end
end
if RUBY_VERSION < '2.3'
Array.send(:include, RubyDig)
Hash.send(:include, RubyDig)
end
How to efficiently build a tree from a flat structure?
Store IDs of the objects in a hash table mapping to the specific object. Enumerate through all the objects and find their parent if it exists and update its parent pointer accordingly.
class MyObject
{ // The actual object
public int ParentID { get; set; }
public int ID { get; set; }
}
class Node
{
public List<Node> Children = new List<Node>();
public Node Parent { get; set; }
public MyObject AssociatedObject { get; set; }
}
IEnumerable<Node> BuildTreeAndGetRoots(List<MyObject> actualObjects)
{
Dictionary<int, Node> lookup = new Dictionary<int, Node>();
actualObjects.ForEach(x => lookup.Add(x.ID, new Node { AssociatedObject = x }));
foreach (var item in lookup.Values) {
Node proposedParent;
if (lookup.TryGetValue(item.AssociatedObject.ParentID, out proposedParent)) {
item.Parent = proposedParent;
proposedParent.Children.Add(item);
}
}
return lookup.Values.Where(x => x.Parent == null);
}
Related Topics
How to Reference a File from Inside of a Gem
How to Export Environment Variable Permanently Using Ruby
The Command Rbenv Install Is Missing
Install Latest Stable Version of Ruby Using Rbenv
How to Describe an Enumeration Column in a Rails 3 Migration
Adding Attributes to a Ruby Object Dynamically
How to Password-Protect My /Sidekiq Route (I.E. Require Authentication for the Sidekiq::Web Tool)
How to Get All Class Names in a Namespace in Ruby
Could Not Find a Valid Gem 'Rails' (>= 0) in Any Repository
Troubleshooting Ssl Certificates, Ruby, MAC Os X Yosemite
Passing a Hash to a Function ( *Args ) and Its Meaning
Ruby: Is There an Opposite of Include? for Ruby Arrays
Installing the Postgresql Gem with 'Gem Pq' Fails with Error: Failed to Build Gem Native Extension
Using Htaccess Password Protection on Rails
Count the Number of Lines in a File Without Reading Entire File into Memory