avatarJoan Indiana Lyness

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

4215

Abstract

We want to look at one mattress at a time, starting with the top of the stack.</p><p id="ffb7">Now let’s code.</p><p id="8d3f">Remember, we’re going to look at one item at a time, starting with the top of the stack. So let’s use ‘pop’ to pop off the top (last) item in the array. We’ll call it<i> current_item</i>, because it’s the current item we’re looking at.</p><div id="b786"><pre><span class="hljs-keyword">def</span> <span class="hljs-title function_">find_pea</span>(<span class="hljs-params">stack</span>)</pre></div><div id="04d2"><pre><span class="hljs-keyword">let</span> current_item = <span class="hljs-built_in">stack</span>.pop</pre></div><div id="41f4"><pre><span class="hljs-comment">#more code here</span>

<span class="hljs-keyword">end</span></pre></div><p id="6e0b">When we look our current item, we’re going to do one of two things. If it’s the pea, our work is done! But if it’s another mattress, we’ll have to start all over again.</p><div id="81f5"><pre> <span class="hljs-keyword">if</span> current_item === <span class="hljs-string">"pea"</span> <span class="hljs-keyword">return</span> <span class="hljs-string">"found! Now I can get a good night's sleep"</span> <span class="hljs-keyword">else</span> puts <span class="hljs-string">"No pea here!"</span> <span class="hljs-built_in">find_pea</span>(stack) end</pre></div><p id="c6bf">There are two things going on here (not in this order …)</p><ol><li>If we don’t find the pea, the function calls itself again, passing in <i>stack</i> as an argument.</li><li>We establish a way to exit the function instead of calling it again. that’s called a “base case”. Our base case is finding the pea. Once found, our work is done. We return a value (a string in this case). In Ruby, the return makes us exit the loop. Since there is no more logic after the loop, we also exit the entire function.</li></ol><p id="db01"><i>Warning:</i> Without a base case, a recursive method will call itself again and again and again … in other words, it will be an infinite loop.</p><p id="6f08">So far, we have this:</p><div id="372e"><pre><span class="hljs-function">def <span class="hljs-title">find_pea</span><span class="hljs-params">(stack)</span>

current_item </span>= stack.<span class="hljs-built_in">pop</span>()</pre></div><div id="bdfb"><pre><span class="hljs-keyword">if</span> current_item === <span class="hljs-string">"pea"</span> <span class="hljs-meta">#base case:</span> <span class="hljs-keyword">return</span> <span class="hljs-string">"found! Now I can get a good night's sleep!"</span> <span class="hljs-keyword">else</span> puts <span class="hljs-string">"This is not a pea! This #{current_item}"</span> <span class="hljs-built_in">find_pea</span>(stack) end end</pre></div><div id="fbb4"><pre><span class="hljs-function"><span class="hljs-title">find_pea</span><span class="hljs-params">(stack)</span></span></pre></div><h1 id="fe52">Wait, what if there’s NO pea?</h1><p id="0c99">We included a pea in our test array, but what if we want to test our method against different piles of mattresses that may or may not include a pea? If there’s no pea under the last mattress of any given stack of mattresses, our function should stop.</p><p id="2d99">But the way we wrote it, it keeps going. After we’re done with the last mattress, it will pass an empty array <code>stack = []</code> back into the argument. When we run this line</p><div id="a91c"><pre><span class="hljs-attr">current_item</span> = stack.pop()</pre></div><p id="a357"><i>current_item</i> will equal <i>nil</i>. Then we’ll check to see if <i>nil</i> is equal to “pea” and of course it won’t be, so we end up calling find_pea(stack) again. In other words, we created an … infinite loop! AAAGH!</p><figure id="2d33"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*8Ld01azTfdIByjx4ahPgvg.png"><figcaption>The Scream, by Edvard Munch</figcaption></figure><h1 id="38d2">We need another base case</h1><p id="61c7">Recursive methods have at least one base case. Our first base case exits the function when we find the pea. Our second base case should exit the function if we finish looking through all of the mattresses

Options

without finding the pea.</p><p id="e738">Each time we start the loop, let’s see if our stack is empty. If it is, let’s exit by returning a value.</p><div id="1f83"><pre> <span class="hljs-keyword">if</span> stack.length > <span class="hljs-number">0</span> current_item = stack.<span class="hljs-built_in">pop</span>() <span class="hljs-keyword">else</span> <span class="hljs-keyword">return</span> <span class="hljs-string">"drat! couldn't find it!"</span> end</pre></div><p id="cfe4">All together now:</p><figure id="aca0"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*AXgFo3JVQpbVIEZyILI7Kw.png"><figcaption>Recursive function for finding the offending legume!</figcaption></figure><p id="e49a"><a href="http://www.pythontutor.com/visualize.html#code=%0Astack%20%3D%20%5B%22mattress1%22,%20%22pea%22,%20%22mattress2%22,%20%22mattress3%22,%20%22mattress4%22%5D%0A%0Adef%20find_pea%28stack%29%0A%0A%20%20if%20stack.length%20%3E%200%0A%20%20%20%20current_item%20%3D%20stack.pop%28%29%0A%20%20else%0A%20%20%20%20return%20%22drat!%20couldn't%20find%20it!%22%0A%20%20end%0A%0A%20%20if%20current_item%20%3D%3D%3D%20%22pea%22%0A%20%20%20%20return%20%22found!%20Now%20I%20can%20get%20a%20good%20night's%20sleep%22%0A%20%20else%0A%20%20%20%20puts%20%22No%20pea%20here,%20instead%20I%20found%20%23%7Bcurrent_item%7D%22%0A%20%20%20%20find_pea%28stack%29%0A%20%20end%0Aend%0A%0Afind_pea%28stack%29&amp;cumulative=false&amp;curInstr=4&amp;heapPrimitives=nevernest&amp;mode=display&amp;origin=opt-frontend.js&amp;py=ruby&amp;rawInputLstJSON=%5B%5D&amp;textReferences=false">You can step through the code here, on PythonTutor.com</a>(which uses many languages, including Ruby, despite the name!)</p><p id="0575"><a href="https://repl.it/@Joan_IndianaInd/Princess-and-Pea-Recursion">You can also play with it here, on repl.it.</a></p><h1 id="1c2b">Back to real life</h1><p id="69da">In real life, you do not use recursion to search for a particular string in an array of five strings (there are way easier ways to do that, which I won’t cover here!).</p><p id="e75f">So when do you use recursion? You use it when you need to run the same operation on progressively smaller or more deeply nested parts of a problem.</p><p id="2fe9">The classic use case for recursion is to traverse a file tree, which you could do like so:</p><div id="8391"><pre>pseudocode for printing names of <span class="hljs-built_in">all</span> pdfs <span class="hljs-keyword">in</span> <span class="hljs-keyword">file</span> tree</pre></div><div id="fd39"><pre>def recursively_search_file_tree(<span class="hljs-built_in">directory</span>) <span class="hljs-keyword">if</span> <span class="hljs-built_in">directory</span> is <span class="hljs-literal">empty</span> <span class="hljs-literal">return</span> <span class="hljs-string">"all done!"</span> <span class="hljs-keyword">else</span> <span class="hljs-built_in">directory</span>.<span class="hljs-keyword">each</span> <span class="hljs-built_in">do</span> |<span class="hljs-keyword">item</span>| <span class="hljs-keyword">if</span> <span class="hljs-keyword">item</span> is <span class="hljs-keyword">a</span> <span class="hljs-built_in">file</span> <span class="hljs-keyword">with</span> <span class="hljs-built_in">extension</span> .pdf puts <span class="hljs-keyword">item</span> name elsif <span class="hljs-keyword">item</span> is <span class="hljs-keyword">a</span> <span class="hljs-built_in">folder</span> recursively_search_file_tree(<span class="hljs-built_in">folder</span>) <span class="hljs-function"><span class="hljs-keyword">end</span> <span class="hljs-title">end</span></span> <span class="hljs-function"><span class="hljs-keyword">end</span> <span class="hljs-title">end</span></span></pre></div><p id="8251">Here’s hoping you like recursion a little more than you did at the start of this post!</p><p id="5089">Copyright © Joan Indiana Lyness 2019</p><p id="48f0"><i>in case you missed it: <a href="https://readmedium.com/algorithms-101-birthday-chocolate-in-javascript-f5fcbd639bf3">Algorithms 101, #10, Birthday Chocolate in JavaScript</a></i></p></article></body>

Algorithms 101: Princesses, Peas and Recursion in Ruby

Noob v. Algorithms, #11, how I learned to stop hating recursion

The Princess and the Pea, 1911 illustration by Edmund DuLac

Do you FEAR recursion? Well, fellow Noobs, I did too, as recently as a few days ago. I had read many excellent blog posts about recursion, and I felt like I understood a bit of it. But just hearing the word made me slightly ill.

My aha moment came from … Grokking Algorithms by Aditya Bhargava. If this isn’t a best seller, I’m not sure why not! (No, I don’t get any money for promoting this book). But if you want a great explanation with big, beautiful drawings, this book is for you. Here is a free preview . (I ended up buying a used(?) version of the e-book on eBay for $5).

Short and sweet intro: A recursive function is one that calls itself. Now for the explanation …

The Princess and the Pea

Do you remember this Hans Christian Anderson fairy tale? In it, a prince wants to marry a princess, but he wants to marry a real princess.

How will he know if she’s real? Well, a real princess is super delicate(humor me, I didn’t write the tale, Hans did). She is sooooo delicate that if she slept on a pile of mattresses, and if there were a pea anywhere in that pile, our delicate princess would not be able to sleep because the pea would offend her delicate self. Mere mortals, of course, would never notice.

To learn recursion, let’s imagine that you are sleeping on top of a stack of mattresses, and you notice something trying to poke through. Probably a pea! You can’t sleep, so you try to find it. You are determined. You are going to look under one mattress at a time until you can find and remove find the offending legume!

Photo by Rachael Gorjestani on Unsplash

Steps for finding the pea

Let’s say you want to write instructions for how to find the pea. You could say:

  1. look under the top mattress.
  2. If you find the pea, your work is done!
  3. If you another mattress, look under it.
  4. If you find the pea, your work is done!
  5. If you find another mattress, look under it
  6. If you find the pea, your work is done!
  7. If you find another mattress….

Obviously, there’s a pattern here. Those 7 steps above are really just 3 simple steps, repeated:

  1. Look under mattress
  2. If you find a pea, your work is done! Forget about step 3. Woot!
  3. If you find another mattress, start again from step 1.

Stack of mattresses

So here’s what a stack of mattresses would look like in code:

Suspension of disbelief

For the sake of learning the concept of recursion, forget what you know about arrays for a moment and try to imagine the items above as being in a physical stack. The first item in the array is at the bottom of the stack. We want to look at one mattress at a time, starting with the top of the stack.

Now let’s code.

Remember, we’re going to look at one item at a time, starting with the top of the stack. So let’s use ‘pop’ to pop off the top (last) item in the array. We’ll call it current_item, because it’s the current item we’re looking at.

def find_pea(stack)
let current_item = stack.pop
#more code here
   
end

When we look our current item, we’re going to do one of two things. If it’s the pea, our work is done! But if it’s another mattress, we’ll have to start all over again.

  if current_item === "pea"
    return "found! Now I can get a good night's sleep"
  else
    puts "No pea here!"
    find_pea(stack)
  end

There are two things going on here (not in this order …)

  1. If we don’t find the pea, the function calls itself again, passing in stack as an argument.
  2. We establish a way to exit the function instead of calling it again. that’s called a “base case”. Our base case is finding the pea. Once found, our work is done. We return a value (a string in this case). In Ruby, the return makes us exit the loop. Since there is no more logic after the loop, we also exit the entire function.

Warning: Without a base case, a recursive method will call itself again and again and again … in other words, it will be an infinite loop.

So far, we have this:

def find_pea(stack)

current_item = stack.pop()
if current_item === "pea"
    #base case:
    return "found! Now I can get a good night's sleep!"
  else
    puts "This is not a pea! This #{current_item}"
    find_pea(stack)
  end
end
find_pea(stack)

Wait, what if there’s NO pea?

We included a pea in our test array, but what if we want to test our method against different piles of mattresses that may or may not include a pea? If there’s no pea under the last mattress of any given stack of mattresses, our function should stop.

But the way we wrote it, it keeps going. After we’re done with the last mattress, it will pass an empty array stack = [] back into the argument. When we run this line

current_item = stack.pop()

current_item will equal nil. Then we’ll check to see if nil is equal to “pea” and of course it won’t be, so we end up calling find_pea(stack) again. In other words, we created an … infinite loop! AAAGH!

The Scream, by Edvard Munch

We need another base case

Recursive methods have at least one base case. Our first base case exits the function when we find the pea. Our second base case should exit the function if we finish looking through all of the mattresses without finding the pea.

Each time we start the loop, let’s see if our stack is empty. If it is, let’s exit by returning a value.

  if stack.length > 0
    current_item = stack.pop()
  else
    return "drat! couldn't find it!"
  end

All together now:

Recursive function for finding the offending legume!

You can step through the code here, on PythonTutor.com(which uses many languages, including Ruby, despite the name!)

You can also play with it here, on repl.it.

Back to real life

In real life, you do not use recursion to search for a particular string in an array of five strings (there are way easier ways to do that, which I won’t cover here!).

So when do you use recursion? You use it when you need to run the same operation on progressively smaller or more deeply nested parts of a problem.

The classic use case for recursion is to traverse a file tree, which you could do like so:

pseudocode for printing names of all pdfs in file tree
def recursively_search_file_tree(directory)
   if directory is empty 
      return "all done!"
   else 
      directory.each do |item|
        if item is a file with extension .pdf 
           puts item name
        elsif item is a folder
           recursively_search_file_tree(folder)
        end
     end
   end
end

Here’s hoping you like recursion a little more than you did at the start of this post!

Copyright © Joan Indiana Lyness 2019

in case you missed it: Algorithms 101, #10, Birthday Chocolate in JavaScript

Ruby
Algorithms
Recursion
Coding
Recommended from ReadMedium