Tag Archives: loops

The Locker Problem

I was recently given a puzzle to solve in Ruby called “The Locker Problem”. Hearing it for the first time kind of made me feel overwhelmed, but that’s what motivated me to try to solve it. After a lot of thinking, I’ve finally figured it out. The solution actually ended up being a lot simpler than I made it out to be in my head. Here’s the puzzle, as well as the solution and my thought process in solving it:

In front of you, there are 100 open gym lockers in a row.
You walk around the entire row 100 times. The first time,
you stop at each locker and close all the opened ones. The
second time around, you stop at each 2nd locker and open
the ones that are closed. The third time around, you stop at each
3rd locker and close the ones that are opened and open the ones
that are closed. You continue this pattern until you’ve done it a
total of 100 times.
At the end, which lockers are opened and which are closed?

Did reading that puzzle make your head hurt? This is actually pretty simple to solve after breaking it down piece by piece. First, I’ll show you my solution:

Ruby

As you can see, it doesn’t take a lot of code to solve this puzzle but there’s a lot going on. Let’s break it down.

First we create an array representing 100 opened lockers (true == open). For our loop that will represent walking around the lockers 100 times, we use 'i' as a placeholder and assign 1 to it. This will represent the first time walking around the lockers, stopping at each locker. Therefore, 'i' will represent the rounds we take around the lockers. At first glance, it may seem to you that we’re only walking around the lockers 99 times but remember that we’re already starting at the first round (i = 1) and therefore adding 1 to 'i' 99 more times. Totaling 100 times that we’ll walk around the lockers.

(0..open_lockers.size - 1) is a range from 0-99 that represents the index positions of all 100 lockers in our array. .step is a method that iterates through a range and passes every nth element to the supplied block. For example, lets say we’re walking around the lockers for the 2nd time. This means that 2 will be supplied to the .step method as a parameter. .step will then start at 0 and pass each 2nd element to the block, including 0. (0, 2, 4, 6, 8,…). If this made you notice a potential problem with properly identifying the lockers, then you’re doing great (I figured it out the hard way). The problem is that if we’re trying to identify every 2nd locker, the 0, 2, 4, 6, 8,… index positions are actually going to identify the 1st, 3rd, 5th, 7th, 9th,… lockers. This is why we subtract 1 from the index positions to properly identify the correct locker that we’re trying to access within the array. So in actuality, the index positions we’ll be accessing are [-1, 1, 3, 5, 7,…]. This will properly identify every 2nd locker (100th, 2nd, 4th, 6th, 8th,…98th). Now we can be certain that all 100 times that we walk around the lockers, we’ll be closing or opening the correct ones.

We then use a boolean expression (or flow control) that represents closing a locker if it is open, or opening a locker if it is closed.

Lastly, we pass the each_with_index method to the open_lockers array that iterates
through the array, grabbing each locker and it’s index position. We then use string interpolation to add 1 to the index position to properly display the locker onto the screen. i.e. Locker #1 instead of Locker #0 (that wouldn’t make much sense). We also use string interpolation to display “Opened” onto the screen if the locker is ‘true’ or “Closed” if ‘false’.

Advertisements
Tagged , , , , ,

What I learned today: The for iterator

I was playing around with some practice exercises in Ruby today when I came across this sample code:ruby rails

This defines a method called parks_per_city which takes in an array of hashes as an argument and maps a city to the number of parks located within that city. Example :

ruby

This is done by looking at the value associated with the us_city key – which will be some city, supplying that value to the city hash as a key, and setting the value equal to 1 if that city doesn’t already exist, or adding to the value ( the number of parks ) if a city already exists as a key within the hash.
What I had not seen before is the line before the do..end block:

for park_city in parks

Even though it becomes obvious what this code does by reading the 11 lines of code above, I decided to google it to understand HOW this works. After researching different resources online, I found myself asking “Is it a loop method? Is it an iterator method? Is it both?”. According to this great blog called Snorks, it is a loop method that acts like an iterator without actually having to take a block. Here’s an example taken directly from the Snorks blog post:

ruby

However, when looking at the first screen-shot above, we see that the for loop is passed a do..end block. Then I read Chris Pines’ “Learn to Program” book – which I highly recommend if you’re a beginner like myself trying to learn Ruby and Rails. In chapter 7, he mentions that iterators are always followed by blocks such as do..end or {...}. He also goes on to mention that these blocks are only used with iterators. Hmm… So which is it, an iterator or a loop? I’m sure this probably won’t bother most people, but not being able to figure this out is bugging the hell out of me. So to better understand how this code works and hoping it would provide some insight on whether it’s a loop or an iterator, I decided to re-write the code using an iterator method I’m already familiar with and testing the parks_per_city method to see if it works. I used the each iterator. Here’s the code I wrote: ruby

As you can see, by replacing: for park_city in parks do... with parks.each do |park_city|... I was able to accomplish the same task. This each iterator method is pretty straight forward. It grabs each hash in the parks array and assigns it to the park_city variable as a hash. It then checks to see if the us_city in question is supplied to the city hash as a key. If not, then it’ll include the key to the hash and set the value equal to 1. If the city hash already has the us_city as a key then, it will add to the number of parks in that city.

I therefore can’t help but to conclude that:
for value in iterable do
...
end

in this context is an iterator method that executes whatever is in the block; just like:
iterable.each do |value|
...
end
.

Am I correct in my conclusion? What are your thoughts? Leave a comment below and let me know what you think!

Tagged , , , , ,
%d bloggers like this: