Iterate Over a Deeply Nested Level of Hashes in Ruby

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



Leave a reply



Submit