I am writing a small helper to walk a hash or an array of arrays to
find a nested key. (by the way, if there is an existing function for
this in Ruby I will willingly take it instead).
The call is this
keywalk(collection, key)
the def is this
def keywalk(collection,key)
key = key.to_s
collection.each do |check|
return check[1] if check[0] == key
keywalk(check,key) if (check.is_a?(Array) or check.is_a?(Hash))
end
nil
end
The problem that I have is that key is always nil inside
collection.each even though it is define inside the method and a puts
shows that it has the value passed as that parameter. Why is key
evidently out of scope inside the iterator?
  keywalk(check,key) if (check.is_a?(Array) or check.is_a?(Hash))
 end
 nil
end
The problem that I have is that key is always nil inside
collection.each even though it is define inside the method and a puts
shows that it has the value passed as that parameter. Â Why is key
evidently out of scope inside the iterator?
blocks can see variables created outside them (but local variables
created inside the block do not persist outside it)
Your keywalk function will however almost always return nil - when you
recurse and call keywalk a second time you are ignoring the return
value
blocks can see variables created outside them (but local variables
created inside the block do not persist outside it)
Your keywalk function will however almost always return nil - when you
recurse and call keywalk a second time you are ignoring the return
value
Fred
OK. Then I am missing something simple. And, I am probably trying
too hard. I will revisit the problem.
I am clearly misunderstanding something fundamental about ruby methods
and the return statement.
I have finally gone for the blunt force solution so that I can follow
along with what is happening.
def keywalk(tcoll,tkey,result=nil)
if result
puts("result returned = #{result}")
return result
end
print tcoll.to_yaml
puts("")
tcoll.each_pair do | tk, tv |
puts("tkey is #{tkey} and tk is: #{tk} and tv is #{tv}")
if tk.to_s == tkey.to_s
puts("keys are equal and tv is #{tv}")
result = { tkey => tv.to_s }
puts("The result is = #{result}")
return
end
if tv.kind_of?(Array)
puts("Array = #{tv.inspect}")
tv.each do |tva|
if tva.kind_of?(Hash)
keywalk(tva,tkey,result)
end
end
elsif tv.kind_of?(Hash)
puts("Hash = #{tv.inspect} class is #{tv.class}")
keywalk(tv,tkey,result)
else
# puts("Something else = #{tv.inspect} with class #
{tv.class}")
end
end
puts(“The final result was = #{result}”)
result
end
Why, even when I finally find the inner key which this does
accomplish, do I always get nil returned? What do I misapprehend
about returns?
tkey is user_id and tk is: user_id and tv is 339
keys are equal and tv is 339
The result is = user_id339
This is what keywalk returns:
Thank you for pointing out the error with the return. I fixed that
and and then finally realised that I was not assigning my return value
when calling the method recursively. This was why the result was
disappearing after I found it.
The final code looks like this:
def keywalk(tcoll,tkey,result=nil)
tcoll.each_pair do | tk, tv |
if tk.to_s == tkey.to_s
result = { tkey => tv.to_s }
return result if result
end
if tv.kind_of?(Array)
puts("Array = #{tv.inspect}")
tv.each do |tva|
if tva.kind_of?(Hash)
result = keywalk(tva,tkey,result)
return result if result
end
end
elsif tv.kind_of?(Hash)
puts("Hash = #{tv.inspect} class is #{tv.class}")
result = keywalk(tv,tkey,result)
return result if result
end
end
return result
end
A bit bit wordy but at least I can follow along with it in my head.
Regards,
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.