Iterate over a deeply nested level of hashes in Ruby
If I understand the goal, then you should be able to pass in the parent to your save method. For the top level, it will be nil. The following shows the idea where puts
is used as a place holder for the "save".
def save_pair(parent, myHash)
myHash.each {|key, value|
value.is_a?(Hash) ? save_pair(key, value) :
puts("parent=#{parent.nil? ? 'none':parent}, (#{key}, #{value})")
}
end
Here is an example call to it:
hash = Hash.new
hash["key1"] = "value1"
hash["key2"] = "value2"
hash["key3"] = Hash.new
hash["key3"]["key4"] = "value4"
hash["key3"]["key5"] = "value5"
hash["key6"] = Hash.new
hash["key6"]["key7"] = "value7"
hash["key6"]["key8"] = Hash.new
hash["key6"]["key8"]["key9"] = "value9"
save_pair(nil, hash)
How to iterate over deep nested hash without known depth in Ruby
So, you want to parse recursively until there are no more levels to parse into.
It’s super common in software and referred to as “recursion”. Have a search around to learn more about it - it’ll come up again and again in your journey. Welcome to ruby btw!
As for your actual current problem. Have a read of https://mrxpalmeiras.wordpress.com/2017/03/30/how-to-parse-a-nested-yaml-config-file-in-python-and-ruby/
But also, consider the i18n gem. See this answer https://stackoverflow.com/a/51216931/1777331 and the docs for the gem https://github.com/ruby-i18n/i18n This might fix your problem of handling internationalisation without you having to get into the details of handling yaml files.
Iterate nested hash that contains hash and/or Array
It is not entirely clear what you might want, but both Array
and Hash
implement each
(which, in the case of Hash
, is an alias for each_pair
).
So to get exactly the output you would get if your method would work, you could implement it like this:
def iterate(h)
h.each do |k,v|
# If v is nil, an array is being iterated and the value is k.
# If v is not nil, a hash is being iterated and the value is v.
#
value = v || k
if value.is_a?(Hash) || value.is_a?(Array)
puts "evaluating: #{value} recursively..."
iterate(value)
else
# MODIFY HERE! Look for what you want to find in the hash here
# if v is nil, just display the array value
puts v ? "key: #{k} value: #{v}" : "array value #{k}"
end
end
end
How to iterate over a hash that contains deep nested array using helper method in rails
If you had more than one address to look up, you might do this:
HASH_TABLE.each_with_object({}) { |(_,v),h|
v.each { |type, value| h[value] = type } }
#=> {"56H"=>"Manager", "56A"=>"Admin", "56B"=>"Policy",
# "78C"=>"Temp Member", "764"=>"Guest", "55H"=>"Worker",
# "55A"=>"Employee", "55B"=>"Guest", "764AA"=>"NA"}
h["56H"] #=> "Manager"
h["55B"] #=> "Guest"
Two other ways of constructing the hash:
h = Hash[HASH_TABLE.values.flatten(1).map(&:reverse)]
and
h = Hash[HASH_TABLE.values.flatten(1)].invert
If the same "key" (e.g., "Employee"
) were in both HASH_TABLE['Users']
and HASH_TABLE['Visitor']
, this might be more useful:
h = HASH_TABLE.each_with_object({}) { |(k,v),h|
v.each { |type, value| h[value] = [k, type] } }
# => {"56H" =>["Users", "Manager"], "56A"=>["Users", "Admin"],
# "56B" =>["Users", "Policy"], "78C"=>["Visitor", "Temp Member"],
# "764" =>["Users", "Guest"], "55H"=>["Visitor", "Worker"],
# "55A" =>["Visitor", "Employee"], "55B"=>["Visitor", "Guest"],
# "764AA"=>["Visitor", "NA"]}
h["56H"] #=> ["Users", "Manager"]
h["55B"] #=> ["Visitor", "Guest"]
iterate through nested hashes using conditionals in Ruby
You can use something like
h = {}
languages.each do |k, v| # oo or func
v.each do |k1, v1| # ruby/python
if h[k1]
h[k1][:style] << k
else
h[k1] = {type: v1[:type], style: [k]}
end
end
end
It checks to see that h
is defined, and if so, appends to its array. Otherwise it defines the entire hash with your type and a style array of size 1.
Looping through a nested hash
{key1: "value1", key2: {key3: "value2", key4: "value3"}}
Your hash is not consistent hash of hashes, in the first iteration, value
is value1
which is a string, and you cannot iterate over a string
.
to avoid that, you can check beforehand like,
hash.each do |key,value|
p key
if value.is_a?(Hash)
value.each do |k,v|
p k
p v
end
else
p value
end
end
My goal is to access the values of key3 and key4. (I want to put them in a variable of some kind to be used elsewhere)
you can traverse a hash based on key associations. As per your need above, you can simply do:
hash[:key2][:key3]
#=> "value2"
hash[:key2][:key4]
#=> "value3"
Ruby - Iterating over a Nested Hash and counting values
Are you looking for something like this?
RULES = {
:limb => {
:colour => {
'a' => 'foo',
'b' => 'bar'
},
'c' => 'baz',
:color => {
'b' => 'baz'
}
}
}
def count_letters(hash, results = {})
hash.each do |key, value|
if value.kind_of?(Hash)
count_letters(value, results)
else
results[key] = (results[key] || 0) + 1
end
end
results
end
p count_letters(RULES)
Related Topics
How to Use Hash Keys as Methods on a Class
Get Single Char from Console Immediately
Why Do I Get Uninitialized Constant Devise Name Error When Running Webrick Server
Nokogiri Was Built Against Libxml Version 2.7.7, But Has Dynamically Loaded 2.7.3
How to Map/Collect with Index in Ruby
"Which in Ruby": Checking If Program Exists in $Path from Ruby
Error Installing Nokogiri on Bundle Install But Already Installed
Ruby CSV - Get Current Line/Row Number
Rails 4 Migration: How to Reorder Columns
Is There an Expect Equivalent Gem for Ruby
Split String into a List, But Keeping the Split Pattern
Double-Splat Operator Destructively Modifies Hash - Is This a Ruby Bug
Update Just One Gem with Bundler