Exercise 9 of 10 · Putting it together
Rainfall Week
What you will make
A seven-day rainfall report with a line for every day, the week added up underneath it, and the single wettest day picked out.
The one new idea: a variable created before a loop carries a running total from pass to pass
Adding up as you go, and remembering the best you have seen so far, sit underneath an enormous number of ordinary programs — a shopping total, a high score, a longest streak. Each one is a variable started before a loop and changed inside it.
Go straight to the code ↓A variable that outlives the loop
There is no new syntax here. An array, .each, an if, interpolation, + — every piece has already been met. What is new is getting them to work together, which is a different skill from knowing each one on its own.
The idea that joins them up is small, but worth being precise about. A variable created before a loop is still standing on every pass through it, and still standing after the loop ends — a block in Ruby can read and change a variable from outside it, unlike a method definition. Whatever one pass leaves in that variable is what the next pass finds. Put the line that sets the starting value inside the loop instead, and it runs again every time round, throwing away whatever the pass before it left there.
A running total. Start a variable at zero above the loop, then inside it write total = total + mm. Ruby works out the right-hand side first — whatever total was a moment ago, plus this pass's value — and stores the answer back under the same name.
The best so far. Start a second variable at zero above the loop, then ask if mm > wettest_mm inside it. When the current value beats the record, store it. By the final pass, the largest value seen so far is simply the largest there is.
A worked example
coins = [3, 7, 2, 7]
total = 0
biggest = 0
coins.each do |coin|
total = total + coin
if coin > biggest
biggest = coin
end
puts "coin #{coin} total #{total}"
end
puts "biggest coin: #{biggest}"coin 3 total 3
coin 7 total 10
coin 2 total 12
coin 7 total 19
biggest coin: 7total never drops back to zero, because that line sits above the loop and runs once. biggest stops changing after the second coin, even though the last coin is also a 7 — 7 > 7 is false, so a tie leaves the first one standing.
Your turn
The editor holds a week of rainfall. Press Run first: the chart itself is correct, but the total reads 0 mm and the wettest day comes out as day 0, which is not one of the real seven days.
Both additions go inside the loop, lined up with the puts above them: add this day's rain to total, and if it beats wettest_mm, store both the new amount and the day number.
If something goes wrong
If the total reads far too low, check that the line sits inside the loop, not after its end. If the millimetres come out right but the day stays 0, the if is updating wettest_mm alone — wettest_day needs setting in the same block.
Write your code
Runs in your browser. Press Run (or Ctrl/Cmd+Enter) and the output is checked for you.
Press Esc then Tab to move keyboard focus out of the code editor.
Output will appear here after you run your code.The runtime is starting in the background. You can type now — it will be ready before you are.
The answer appears here once you have run your code at least once.
Things that often go wrong here
- Writing total = total + mm after the loop's end instead of inside it
- A line placed after the each block's end runs once, after every day has already gone past, and by then mm no longer exists at all outside the block — Ruby stops with NameError: undefined local variable or method 'mm'.
- Setting total = 0 inside the loop
- Putting the starting value inside the block wipes out every day before it, on every single pass, so the week ends up totalling only the last day's rain. A starting value belongs above the loop, where it runs exactly once.
- Updating wettest_mm but forgetting wettest_day
- An if that only changes wettest_mm leaves wettest_day holding the zero it started with, so the final line claims the wettest day was day 0 — not one of the seven real days. Both lines belong inside the same if, because they are two halves of one fact.
- Writing if mm = wettest_mm
- A single = assigns wettest_mm's value into mm rather than comparing them, and Ruby treats that assigned value as true on every pass except when it happens to be nil or false — so the block runs unconditionally while also silently overwriting mm. Ruby's own warning, found '=' in conditional, is worth reading when it appears.
Want a blank editor instead? Open the Ruby playground.