Group: comp.lang.ruby


Subject: Break a recursive loop
From: Just Another Victim of the Ambient Morality
Date: 11/19/2007 1:42:20 PM
"Alvaro Perez" <alvaro.pmartinez@gmail.com> wrote in message news:8b39ce45165efee679037915d6b29bb0@ruby-forum.com... > Hi there, > > something that I think should not be very difficult, but i'm struggling > with: > > def find(name, where) > for father in where > if (father.name==name) then > found = thing > break > else > find(name, father.children) > end > end > found > end > > I have an array with parent objects, some of them have children. I want > to find an object with the same name and return in, otherwise nil. > > The problem is that, once I start searching inside the children of some > father, and I found what I'm looking for, I break the loop inside (array > father.children). But then the search continues in the level above. I > would like to break the complete search. How can it be done? I don't understand, exactly, what you're doing but there are some things that are obviously wrong with your code and some techniques you should probably know to implement what you're doing. First of all, have you tested your own code? Your find() method doesn't even store the value of its recursive call. It might still work if that recursive call is the last thing your method does but you explicitly evaluate the variable "found," ensuring that the recursed value is never returned since it can never be the last thing done. Secondly, using literal for loops is very pythonic and, thus, un-ruby like. Wouldn't you rather where.each through elements? Finally, there are many different ways to solve your problem. If where is enumerable, you can use the find method: def weird_find(name, container) container.find do |father| if father.name == name father # Is this what you're looking for? else weird_find(name, father.children) end end end ...this code is untested but it should work. If "container" has no find() method, just use .each and break, instead. Something cool you could use is throw. This is simple enough to not need it but you could just excercise your ruby-fu: def recursive_find(name, container) container.each do |father| if father.name == name throw :found, father # The second parameter should be catch's return value... else recursive_find(name, father.children) end end end def weird_find(name, container) catch :found { recursive_find(name, container) } end ...this is also untested. catch returns a value, here, so weird_find() will return what catch catches... Good luck with your problem...

Subject: Break a recursive loop
From: Just Another Victim of the Ambient Morality
Date: 11/19/2007 2:07:26 PM
"Just Another Victim of the Ambient Morality" <ihatespam@hotmail.com> wrote in message news:0pg0j.14858$zb2.9793@fe02.news.easynews.com... > > "Alvaro Perez" <alvaro.pmartinez@gmail.com> wrote in message > news:8b39ce45165efee679037915d6b29bb0@ruby-forum.com... >> Hi there, >> >> something that I think should not be very difficult, but i'm struggling >> with: >> >> def find(name, where) >> for father in where >> if (father.name==name) then >> found = thing >> break >> else >> find(name, father.children) >> end >> end >> found >> end >> >> I have an array with parent objects, some of them have children. I want >> to find an object with the same name and return in, otherwise nil. >> >> The problem is that, once I start searching inside the children of some >> father, and I found what I'm looking for, I break the loop inside (array >> father.children). But then the search continues in the level above. I >> would like to break the complete search. How can it be done? > > I don't understand, exactly, what you're doing but there are some > things that are obviously wrong with your code and some techniques you > should probably know to implement what you're doing. > First of all, have you tested your own code? Your find() method > doesn't even store the value of its recursive call. It might still work > if that recursive call is the last thing your method does but you > explicitly evaluate the variable "found," ensuring that the recursed value > is never returned since it can never be the last thing done. > Secondly, using literal for loops is very pythonic and, thus, un-ruby > like. Wouldn't you rather where.each through elements? > Finally, there are many different ways to solve your problem. If where > is enumerable, you can use the find method: > > def weird_find(name, container) > container.find do |father| > if father.name == name > father # Is this what you're looking for? > else > weird_find(name, father.children) > end > end > end Actually, I was hitting the crack pipe pretty hard when I wrote this bit with find(). It doesn't do what I thought it did. You'll just need to use each with break... def weird_find(name, container) container.each do |father| if father.name == name found = father # Is this still what you're looking for? break else found = weird_find(name, container) break if found end end found end ...this is untested but should work...

Subject: Break a recursive loop
From: Just Another Victim of the Ambient Morality
Date: 11/19/2007 2:57:09 PM
"Alvaro Perez" <alvaro.pmartinez@gmail.com> wrote in message news:eca08c6514869f02f906f4b2f2afaa26@ruby-forum.com... > > That last works fine. The problem is that I need an instance variable > @found reset to nil every time I start a new search (which I think is > not very elegant). But it works thought. Which "last" was that? I'm glad you've solved your problem. I'm a little concerned with your confessed use of "instance variable @found." Why is "found" an instance variable? It should probably be a local variable and, thus, you'd never have to worry about "resetting" it every time...

Subject: Break a recursive loop
From: Just Another Victim of the Ambient Morality
Date: 11/19/2007 6:25:40 PM
"Alvaro Perez" <alvaro.pmartinez@gmail.com> wrote in message news:1a42f3dc9ed549e04ba4199668039da6@ruby-forum.com... > > It's the only way that works so far. I need to explore inside the > children and break when I found the correct item or return nil. If it > were a local variable, when I break the loop it continues on the next > level of the tree (and then it would always return nil). Did my examples not work at all? I thought that, at worst, they'd have some bugs that would be easily ironed out... My throw example, if throw works the way I think it does, definitely doesn't continue the recursion. Throw is the non-exception exception. My non-throw exception should also cease the recursion, without the need for a non-stack variable. The recursive function examines the return value of the recursive call, ceases the search if something is found and passes this back down the stack. That's all you have to do to cease the search: pass the found item from one recursive call to the other. This unrolls the stack just as an exception would. Does this really not work?