Let’s dive into Jump Start’s Walk-a-thon Assignment!
My goal? To work with multiple hashes stored inside an array.
Primary requirements were:
- Input
- Earning goal for a walk-a-thon
- Amount earned per lap completed (per person)
- Number of laps completed for 5 people
- Output
- Who earned the most money
- Total amount earned
- Whether the earning goal was met
Optional enhancements included:
- Money displayed with two decimal places
- Amount by which our earning goal was either met or missed
- Account for ties in highest earners
- How to handle 500 walkers
- How to let walkers earn a different amount per lap walked
Here’s my sample run:
How did I write the code? Read more to find out!
First, let’s set the stage for the rest of the program — by defining a few things…
An empty array called walkers_data
sits at the top. It will store our walkers’ names, number of laps completed, and total earnings.
Next, I defined a method called ask
. It accepts a string (called question
) as an argument. User input is assigned to variable answer
. The method returns answer
so we can use it outside the method.
After that, I defined a method called linebreak
. It prints -
65 times. (You know, like a linebreak.)
Now, we put my ask
method to use…and get input from the user!
I call the ask
method twice. My arguments are questions (for number of participants and the earning goal), entered as strings. The resulting answer is converted to an integer with .to_i
.
These answers are assigned to variables — number_of_walkers
and goal
, respectively.
My cute little linebreak
method makes a guest appearance for organization’s sake.
We still need to collect info for each walker, though. So, I’m gonna bust out a handy loop, like so:
A few things are going on here. Let’s take a closer look…
My iterator (or i
) is set to 0
. The number assigned to number_of_walkers
tells my .times
loop how many times to run. (It can be any number given by the user…whether 1, 5 or 500. Sky’s the limit!)
I call my ask
method three times, collecting each walker’s:
- Name
- Number of laps completed
- Amount earned per lap completed
The final question allows walkers to earn different amounts of money per lap (instead of setting everyone to the same dollar amount).
In other words, Annie could be earning $2.50 per lap completed…while Karen is earning $3.00 per lap.
The value assigned to name
is left as a string. The laps
value is converted to an integer with to_i
. And earned_per_lap
is converted to a float with .to_f
.
(I’m doing math with both laps
and earned_per_lap
, so they need to be numbers. Since earned_per_lap
is a dollar amount, I made it a float — aka a decimal number.)
Okay, so we collected more info from walkers. Now it’s time for some calculations!
I calculate the amount earned by multiplying laps
with earned_per_lap
. The resulting value is assigned to earned
.
In other words…after each walker enters their info, the loop calculates how much money they earned.
Next, it prints the amount in a string. I use '%.2f' % earned
to display the number as a dollar amount with two decimal places.
Now that we’ve finished calculating everything, it’s time to store our info inside the walkers_data
array.
For each walker, the loop creates a hash. The hash contains three keys: name
, laps
and earned
.
Each key has a corresponding value. In this case, these values are the info we’ve already stored inside name
, laps
and earned
(separate variables from earlier in the loop).
(Note: The value assigned to earned
has been converted to a float so I can display it as a proper dollar amount later.)
This completed hash is stored inside the walkers_data
array. In other words, each walker has their own hash with their respective info stored inside.
(In hindsight, I probably should have included earned_per_lap
. Even though I don’t use it again for the rest of the program, it should still have been stored somewhere. Something to remember for the future!)
The i
iterator initialized at the top makes sure that we don’t accidentally overwrite anyone’s info (by assigning it an index number that equals i
).
Before the loop repeats, it increments i
by 1
— so each walker can get their own index number.
Finally, some final calculations and output:
You know, I actually had trouble summing up everyone’s money earned.
Turns out I was accidentally feeding a dollar signs into the values being added. (Kinda hard to add dollar strings together, since…you know, they’re not numbers.)
Once I got rid of the dollar signs, adding hash values inside arrays wasn’t that hard.
In this case, I called the .sum
method on walkers_data
. I refer to each hash as h
, and call h[:earned]
— or, the number assigned to each hash’s :earned
key.
It adds every walker’s earned amount together, giving me a sum total. My total is assigned to the variable total_earned
.
Then, we proudly display the number by printing a string…which includes our dollar amount (using '%.2f' %
to display two decimals, of course).
Which walkers earned the most money, though?
First, my linebreak
method makes another guest appearance by printing a separator to the screen.
Next, I print “Highest earning walkers:”
Calling the .each
method on the walkers_data
array cycles through each hash (referred to as walker
here).
A conditional statement nested inside the .each
loop checks who earned the most (and if anyone tied).
It does this by comparing the :earned
key’s value for each walker…to the single :earned
key with the highest value (determined using the .max_by
method). In other words, I compare the highest :earned
dollar amount to each walker’s total dollar amount raised.
If a single walker’s :earned
value equals the highest dollar amount, then their name is printed to the screen.
For ordinal numbering, i
is set to 1
…and increments by 1
before the loop repeats.
Because we’re comparing each walker’s amount raised to a single number, we can have multiple winners.
RAD!
Now let’s take a closer look at how I determined whether (and by how much) we met our goal…
First, I print “GOAL MET?” to the screen. Next, I’ve got a conditional nested inside a conditional.
My conditional checks whether we made our earnings goal. It does this by asking whether total_earned
is greater than or equal to goal
.
If true, it prints “Heck yes!” to the screen…and calculates the difference. In this case, the variable difference
is defined as the difference between total_earned
and goal
.
If our total_earned
matches goal
exactly, then the difference should be 0
. In that case, it should print: “We won by the skin of our teeth, with $0.00 to spare.”
Otherwise, it prints a different string and displays difference
as a dollar amount with 2 decimal places.
What if we don’t meet our goal? The rest of the conditional statement handles that:
If we don’t meet our goal, then the loop answers our question with “Nah, dog.”
The variable difference
is defined as goal
minus total_earned
.
After that, it prints a string that displays difference
as a dollar amount with 2 decimal places.
All in all, I enjoyed this assignment. It pushed me to learn how to work with arrays populated with hashes — and made me want to use similar methods on older code I wrote.
Things I wanna improve
- What happens if a user gives invalid input?
- Where does
earned_per_lap
go after I’m done with it?
References
- Find the highest value in an array full of hashes [Stack Overflow]
- Sum the value of hash inside array [Stack Overflow]