{"id":"useful-techniques-for-loop","slug":"for-loop-again","title":"The for loop again","text":"Since module 14, you've gone through lists mostly with for-each loops, and module 37 added streams. Both hand you the values one at a time, which is often all a loop needs. The traditional `for` loop from module 9 is still the tool when the loop needs numbers of its own: counting down, jumping ahead by more than one, or knowing *where* each value is. The MOOC's section 10.3 names it first among its learning goals, so this module starts with it, as a recap.\n\n### Three parts, any numbers\n\n`for (start; condition; change)`: the start runs once, the condition is checked before every round, and the change runs at the end of every round. Nothing says that the change must be `i++`. The last seconds of a quiz round count down:\n\n```java\nfor (int seconds = 5; seconds >= 1; seconds--) {\n    System.out.println(seconds + \"...\");\n}\nSystem.out.println(\"Time's up!\");\n```\n\n```output\n5...\n4...\n3...\n2...\n1...\nTime's up!\n```\n\nCounting down, the condition turns around too: the loop goes on while `seconds >= 1`. Written as `seconds <= 1`, the condition would be false before the first round (5 isn't at most 1), and the loop would never run, without any error message.\n\nTo jump by more than one, write the change with `+=` or `-=`. Between 2024 and 2040, every fourth year is a leap year:\n\n```java\nfor (int year = 2024; year <= 2040; year += 4) {\n    System.out.println(year + \" is a leap year\");\n}\n```\n\n```output\n2024 is a leap year\n2028 is a leap year\n2032 is a leap year\n2036 is a leap year\n2040 is a leap year\n```\n\n### Loops over indexes\n\nA for-each loop gives you each value, but not its position. When the position matters, loop over the indexes instead, from 0 up to `size() - 1` for a list (`length - 1` for an array). You need the indexes:\n\n- to compare a value with the one before it or after it\n- to go through two lists side by side, with the same index in both\n- to go through a list backwards, or to take only every second value\n\nA school garden measures its sunflower every Monday. The growth in a week is a height minus the height of the week before:\n\n```java\nArrayList<Integer> heights = new ArrayList<>();\nheights.add(12);\nheights.add(19);\nheights.add(31);\nheights.add(30);\nheights.add(45);\nfor (int i = 1; i < heights.size(); i++) {\n    int growth = heights.get(i) - heights.get(i - 1);\n    System.out.println(\"Week \" + i + \": \" + growth + \" cm\");\n}\n```\n\n```output\nWeek 1: 7 cm\nWeek 2: 12 cm\nWeek 3: -1 cm\nWeek 4: 15 cm\n```\n\n- The loop starts from index 1, since the first height has no week before it. Starting from 0, the first round would ask for `heights.get(-1)`, and the program would stop with an IndexOutOfBoundsException.\n- `i < heights.size()` makes the last round the last index, 4.\n- `i` is also the week's number, which a for-each loop wouldn't know.\n\nModule 14's way of removing values from a list, a loop that goes backwards with `for (int i = list.size() - 1; i >= 0; i--)`, is an index loop too. Step 7 shows another way to remove, the iterator.\n\n| The loop needs | Use |\n| --- | --- |\n| each value, from the first to the last | a for-each loop (or a stream) |\n| numbers that count down, or go up in steps | `for` with `--`, `+=` or `-=` |\n| positions: neighbors, two lists at once, going backwards | `for` over the indexes |\n","task":"In `Main.java`, write the method `biggestGrowth(ArrayList<Integer> heights)` with a `for` loop over the indexes. It returns the sunflower's biggest growth from one week to the next: the largest `heights.get(i) - heights.get(i - 1)`. If the sunflower never grew, or the list has fewer than two heights, the method returns 0. The check runs:\n\n```java\nArrayList<Integer> heights = new ArrayList<>();\nheights.add(12);\nheights.add(19);\nheights.add(31);\nheights.add(30);\nheights.add(45);\nSystem.out.println(biggestGrowth(heights));\n```\n\nand expects:\n\n```\n15\n```\n","kind":"code","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> heights = new ArrayList<>();\n        heights.add(12);\n        heights.add(19);\n        heights.add(31);\n        heights.add(30);\n        heights.add(45);\n        System.out.println(biggestGrowth(heights));\n    }\n\n    public static int biggestGrowth(ArrayList<Integer> heights) {\n        return 0;\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Integer> heights = new ArrayList<>();\n        heights.add(12);\n        heights.add(19);\n        heights.add(31);\n        heights.add(30);\n        heights.add(45);\n        System.out.println(biggestGrowth(heights));\n    }\n\n    public static int biggestGrowth(ArrayList<Integer> heights) {\n        int biggest = 0;\n        for (int i = 1; i < heights.size(); i++) {\n            int growth = heights.get(i) - heights.get(i - 1);\n            if (growth > biggest) {\n                biggest = growth;\n            }\n        }\n        return biggest;\n    }\n}\n","hints":["Keep the biggest growth so far in a variable that starts at 0. Then a week in which the plant shrank never replaces it, and a list of one height, or none, gives 0.","Loop with `for (int i = 1; i < heights.size(); i++)`, work out `heights.get(i) - heights.get(i - 1)`, and keep it when it's bigger than the biggest so far."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Integer> heights = new ArrayList<>();\nheights.add(12);\nheights.add(19);\nheights.add(31);\nheights.add(30);\nheights.add(45);\nSystem.out.println(biggestGrowth(heights));\n","expect":"15","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Integer> heights = new ArrayList<>();\nSystem.out.println(biggestGrowth(heights));\nheights.add(50);\nSystem.out.println(biggestGrowth(heights));\nheights.add(48);\nheights.add(40);\nSystem.out.println(biggestGrowth(heights));\n","expect":"0\n0\n0","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Integer> heights = new ArrayList<>();\nheights.add(3);\nheights.add(10);\nheights.add(17);\nheights.add(17);\nheights.add(30);\nheights.add(31);\nSystem.out.println(biggestGrowth(heights));\nArrayList<Integer> other = new ArrayList<>();\nother.add(100);\nother.add(1);\nother.add(90);\nSystem.out.println(biggestGrowth(other) + \" \" + other.size());\n","expect":"13\n89 3","hidden":true}],"require":[{"pattern":"\\bfor\\s*\\([^:;]*;","message":"Use a `for` loop over the indexes, such as `for (int i = 1; i < heights.size(); i++)`."}],"forbid":[{"pattern":"\\bfor\\s*\\([^;)]*:","message":"A for-each loop doesn't know where each height is. Loop over the indexes, so that you can take the height before, at `i - 1`."}],"more":[{"task":"What does this program print?\n","kind":"predict","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        for (int i = 10; i > 0; i -= 4) {\n            System.out.println(i);\n        }\n\n        ArrayList<Integer> heights = new ArrayList<>();\n        heights.add(20);\n        heights.add(26);\n        heights.add(29);\n        heights.add(41);\n        heights.add(50);\n        for (int i = heights.size() - 1; i >= 1; i -= 2) {\n            System.out.println(heights.get(i) - heights.get(i - 1));\n        }\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        for (int i = 10; i > 0; i -= 4) {\n            System.out.println(i);\n        }\n\n        ArrayList<Integer> heights = new ArrayList<>();\n        heights.add(20);\n        heights.add(26);\n        heights.add(29);\n        heights.add(41);\n        heights.add(50);\n        for (int i = heights.size() - 1; i >= 1; i -= 2) {\n            System.out.println(heights.get(i) - heights.get(i - 1));\n        }\n    }\n}\n","hints":["The first loop prints 10, 6 and 2. The next value, -2, isn't above 0, so the loop stops there.","The second loop starts from the last index, 4, and goes down by 2: index 4, then 2. (Index 0 fails `i >= 1`.) Each round prints a height minus the one right before it."],"tests":[{"name":"Output","stdin":"","expect":"10\n6\n2\n9\n3","hidden":false}],"require":[],"forbid":[],"lines":["10","6","2","9","3"]},{"task":"The garden club waters its sunflowers every few days. The program reads two numbers, each on its own line: the day of the month of the first watering, and how many days apart the waterings are. With a `for` loop that steps with `+=`, print every watering day in a month of 30 days, and after them how many waterings there were. For the input `3` and `7` the program prints:\n\n```\nWater on day 3\nWater on day 10\nWater on day 17\nWater on day 24\nWaterings: 4\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int first = Integer.valueOf(scanner.nextLine());\n        int every = Integer.valueOf(scanner.nextLine());\n\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int first = Integer.valueOf(scanner.nextLine());\n        int every = Integer.valueOf(scanner.nextLine());\n        int count = 0;\n        for (int day = first; day <= 30; day += every) {\n            System.out.println(\"Water on day \" + day);\n            count++;\n        }\n        System.out.println(\"Waterings: \" + count);\n    }\n}\n","hints":["The loop variable is the day. It starts from the first watering day, goes on while it's at most 30, and grows by `every` in each round.","`for (int day = first; day <= 30; day += every)`, with a counter that goes up in each round and is printed after the loop."],"tests":[{"name":"Test 1","stdin":"3\n7\n","expect":"Water on day 3\nWater on day 10\nWater on day 17\nWater on day 24\nWaterings: 4","hidden":false},{"name":"Test 2","stdin":"30\n5\n","expect":"Water on day 30\nWaterings: 1","hidden":true},{"name":"Test 3","stdin":"12\n9\n","expect":"Water on day 12\nWater on day 21\nWater on day 30\nWaterings: 3","hidden":true},{"name":"Test 4","stdin":"1\n2\n","expect":"Water on day 1\nWater on day 3\nWater on day 5\nWater on day 7\nWater on day 9\nWater on day 11\nWater on day 13\nWater on day 15\nWater on day 17\nWater on day 19\nWater on day 21\nWater on day 23\nWater on day 25\nWater on day 27\nWater on day 29\nWaterings: 15","hidden":true}],"require":[{"pattern":"\\bfor\\s*\\(","message":"Use a `for` loop."},{"pattern":"\\+=\\s*every\\b","message":"Step from one watering day to the next with `day += every`."}],"forbid":[{"pattern":"\\bwhile\\b","message":"Use a `for` loop, not `while`."}]}]}