In my Rails 6 and Ruby 2.7 app I'm trying to return only these hash elements which hash value is a string. The catch is that this hash has other hashes in it (so it's hash of hashes). Like below:
hash = {
language: 'EN',
details: {
resultRanges: {
book: {
title: 'Dunder Mifflin',
available: true,
rank: -1.0,
label: 'gray',
},
},
},
}
From that hash I should get something like:
{
language: 'EN',
details: {
resultRanges: {
book: {
title: 'Dunder Mifflin',
label: 'gray',
},
},
},
}
I've no clue how to do it. If I use hash.keys
I'll get [:language, :details]
so I cannot use something like hash.select { |k, v| v.is_a?(String) }
because it will give me only the first hash key - {:language=>"EN"}
.
CodePudding user response:
What you need here is a recursion, i.e. a function, calling itself:
def filter_hash(hash)
hash.each_with_object({}) do |(key, value), acc|
acc[key] = value if value.is_a?(String)
acc[key] = filter_hash(value) if value.is_a?(Hash)
end
end
This function checks if the value of your hash is String
, then it saves it, if it's a Hash
it calls itself with that nested Hash
CodePudding user response:
You're looking for a recursive function.
def recursively_delete(hash)
hash.each do |k, v|
if v.is_a?(Hash)
recursively_delete(v)
elsif !v.is_a?(String)
hash.delete(k)
end
end
end
recursively_delete(hash)
p hash
=> {:language=>"EN", :details=> {:resultRanges=>{:book=>{:title=>"Dunder Mifflin", :label=>"gray"}}}}