{"id":"lists-searching","slug":"searching","title":"Searching a list","text":"Is a value in the list, and where? Go through the indexes and compare each value with the one you're looking for. Keep the index of the match in a variable that starts at -1: no real index is -1, so it means \"not found yet\".\n\n```java\nimport java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> shelf = new ArrayList<>();\n        shelf.add(\"atlas\");\n        shelf.add(\"cookbook\");\n        shelf.add(\"diary\");\n        shelf.add(\"novel\");\n\n        String wanted = scanner.nextLine();\n        int found = -1;\n        for (int i = 0; i < shelf.size(); i++) {\n            if (shelf.get(i).equals(wanted)) {\n                found = i;\n                break;\n            }\n        }\n\n        if (found == -1) {\n            System.out.println(\"No \" + wanted + \" on the shelf\");\n        } else {\n            System.out.println(\"The \" + wanted + \" is at index \" + found);\n        }\n    }\n}\n```\n\n```input\ndiary\n```\n\n```output\nThe diary is at index 2\n```\n\n- `shelf.get(i)` is a String, so it's compared with `equals`, as always for Strings.\n- `break` stops the search at the first match. Without it, the loop would go on, and `found` would end up as the index of the last match.\n- Only after the loop is it certain that the value isn't there: `found` is still -1.\n\nFor numbers, keep the value you're looking for in an `int` variable, and `numbers.get(i) == wanted` compares the numbers.\n\n### Every match\n\nTo find all the places a value appears, leave out the `break`, and act on each match inside the loop. Here each six is printed and counted:\n\n```java\nArrayList<Integer> rolls = new ArrayList<>();\nrolls.add(3);\nrolls.add(6);\nrolls.add(2);\nrolls.add(6);\nrolls.add(6);\nrolls.add(1);\n\nint sixes = 0;\nfor (int i = 0; i < rolls.size(); i++) {\n    if (rolls.get(i) == 6) {\n        System.out.println(\"Six on roll \" + (i + 1));\n        sixes++;\n    }\n}\nSystem.out.println(\"Sixes: \" + sixes);\n```\n\n```output\nSix on roll 2\nSix on roll 4\nSix on roll 5\nSixes: 3\n```\n\nLists have ready-made methods for some searches, such as `indexOf` and `contains`, and the next module introduces them. Writing the loop yourself shows how they work, and a loop can do more than they can, like finding every match.\n","task":"A music player repeats its playlist: after the last song, it starts again from the first. Read the song titles, one per line, until `end`. Then read one more title: the song playing now. Print `Up next: ` and the song that comes after it, or `Unknown song` when the title isn't in the playlist. When the song is in the playlist twice, go by its first place. For the input `Night Drive`, `Low Tide`, `Glass Garden`, `end` and `Low Tide` the program prints:\n\n```\nUp next: Glass Garden\n```\n\nAfter `Glass Garden`, the next song would be `Night Drive`.\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> playlist = new ArrayList<>();\n\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> playlist = new ArrayList<>();\n        while (true) {\n            String title = scanner.nextLine();\n            if (title.equals(\"end\")) {\n                break;\n            }\n            playlist.add(title);\n        }\n        String playing = scanner.nextLine();\n        int found = -1;\n        for (int i = 0; i < playlist.size(); i++) {\n            if (playlist.get(i).equals(playing)) {\n                found = i;\n                break;\n            }\n        }\n        if (found == -1) {\n            System.out.println(\"Unknown song\");\n        } else {\n            int next = found + 1;\n            if (next == playlist.size()) {\n                next = 0;\n            }\n            System.out.println(\"Up next: \" + playlist.get(next));\n        }\n    }\n}\n","hints":["First find the index of the song playing now: `int found = -1;`, and a loop that sets `found = i` and breaks at the first match (compare with `equals`).","The next song is at `found + 1`. When that equals `playlist.size()`, there's no such index: the next song is the one at index 0."],"tests":[{"name":"Test 1","stdin":"Night Drive\nLow Tide\nGlass Garden\nend\nLow Tide\n","expect":"Up next: Glass Garden","hidden":false},{"name":"Test 2","stdin":"Night Drive\nLow Tide\nGlass Garden\nend\nGlass Garden\n","expect":"Up next: Night Drive","hidden":true},{"name":"Test 3","stdin":"Night Drive\nLow Tide\nGlass Garden\nend\nMorning Rain\n","expect":"Unknown song","hidden":true},{"name":"Test 4","stdin":"Low Tide\nNight Drive\nLow Tide\nGlass Garden\nend\nLow Tide\n","expect":"Up next: Night Drive","hidden":true},{"name":"Test 5","stdin":"Glass Garden\nend\nGlass Garden\n","expect":"Up next: Glass Garden","hidden":true},{"name":"Test 6","stdin":"end\nLow Tide\n","expect":"Unknown song","hidden":true}],"require":[{"pattern":"\\bplaylist\\.get\\s*\\(","message":"Look through the list with `playlist.get(i)`."},{"pattern":"\\bplaylist\\.size\\s*\\(\\s*\\)","message":"Use `playlist.size()`, in the search loop and to tell whether the song is the last one."},{"pattern":"\\.equals\\s*\\(","message":"Compare the titles with `equals`."}],"forbid":[],"more":[{"task":"Read the weather of each day, one word per line (`sun`, `rain` or `cloud`), until `end`. Keep the days in a list. Then print `Rain on day` and the day's number (counting from 1) for every rainy day, and after them `Rainy days: ` and how many there were. For the input `sun`, `rain`, `cloud`, `sun`, `rain` and `end` the program prints:\n\n```\nRain on day 2\nRain on day 5\nRainy days: 2\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> days = new ArrayList<>();\n\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<String> days = new ArrayList<>();\n        while (true) {\n            String weather = scanner.nextLine();\n            if (weather.equals(\"end\")) {\n                break;\n            }\n            days.add(weather);\n        }\n        int rainy = 0;\n        for (int i = 0; i < days.size(); i++) {\n            if (days.get(i).equals(\"rain\")) {\n                System.out.println(\"Rain on day \" + (i + 1));\n                rainy++;\n            }\n        }\n        System.out.println(\"Rainy days: \" + rainy);\n    }\n}\n","hints":["Loop over every index without `break`, and check `days.get(i).equals(\"rain\")`.","On a match, print the day (`i + 1`) and add one to a counter that starts at 0 before the loop."],"tests":[{"name":"Test 1","stdin":"sun\nrain\ncloud\nsun\nrain\nend\n","expect":"Rain on day 2\nRain on day 5\nRainy days: 2","hidden":false},{"name":"Test 2","stdin":"sun\ncloud\nend\n","expect":"Rainy days: 0","hidden":true},{"name":"Test 3","stdin":"rain\nrain\nrain\nend\n","expect":"Rain on day 1\nRain on day 2\nRain on day 3\nRainy days: 3","hidden":true},{"name":"Test 4","stdin":"cloud\nsun\nsun\nrain\nend\n","expect":"Rain on day 4\nRainy days: 1","hidden":true}],"require":[{"pattern":"\\bdays\\.get\\s*\\(","message":"Go through the list with `days.get(i)`."}],"forbid":[]},{"task":"Time to put the module together. Read a runner's lap times in whole seconds, one per line, until `0`. There's at least one lap. Then print:\n\n- `Laps: ` and the number of laps,\n- `Average: ` and the average lap time, as a decimal number,\n- `Fastest: lap ` and the number of the fastest lap, counting from 1 (on a tie, the earlier lap),\n- `Slower than average:`, and after it `lap ` and the number of every lap whose time is above the average, one per line.\n\nFor the input `64`, `61`, `58`, `60`, `63` and `0` the program prints:\n\n```\nLaps: 5\nAverage: 61.2\nFastest: lap 3\nSlower than average:\nlap 1\nlap 5\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<Integer> laps = new ArrayList<>();\n\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        ArrayList<Integer> laps = new ArrayList<>();\n        while (true) {\n            int time = Integer.valueOf(scanner.nextLine());\n            if (time == 0) {\n                break;\n            }\n            laps.add(time);\n        }\n\n        int total = 0;\n        for (int i = 0; i < laps.size(); i++) {\n            total += laps.get(i);\n        }\n        double average = (double) total / laps.size();\n\n        int fastest = 0;\n        for (int i = 1; i < laps.size(); i++) {\n            if (laps.get(i) < laps.get(fastest)) {\n                fastest = i;\n            }\n        }\n\n        System.out.println(\"Laps: \" + laps.size());\n        System.out.println(\"Average: \" + average);\n        System.out.println(\"Fastest: lap \" + (fastest + 1));\n        System.out.println(\"Slower than average:\");\n        for (int i = 0; i < laps.size(); i++) {\n            if (laps.get(i) > average) {\n                System.out.println(\"lap \" + (i + 1));\n            }\n        }\n    }\n}\n","hints":["Work in parts, after reading the list: a loop for the sum (then the average with `(double) total / laps.size()`), a loop for the index of the fastest lap, and a loop that prints the slow laps.","The fastest lap is the smallest time: keep its index, and compare with `laps.get(i) < laps.get(fastest)`. A lap is slow when `laps.get(i) > average`."],"tests":[{"name":"Test 1","stdin":"64\n61\n58\n60\n63\n0\n","expect":"Laps: 5\nAverage: 61.2\nFastest: lap 3\nSlower than average:\nlap 1\nlap 5","hidden":false},{"name":"Test 2","stdin":"70\n0\n","expect":"Laps: 1\nAverage: 70.0\nFastest: lap 1\nSlower than average:","hidden":true},{"name":"Test 3","stdin":"60\n60\n60\n0\n","expect":"Laps: 3\nAverage: 60.0\nFastest: lap 1\nSlower than average:","hidden":true},{"name":"Test 4","stdin":"55\n70\n52\n66\n0\n","expect":"Laps: 4\nAverage: 60.75\nFastest: lap 3\nSlower than average:\nlap 2\nlap 4","hidden":true},{"name":"Test 5","stdin":"48\n50\n48\n53\n0\n","expect":"Laps: 4\nAverage: 49.75\nFastest: lap 1\nSlower than average:\nlap 2\nlap 4","hidden":true}],"require":[{"pattern":"\\blaps\\.size\\s*\\(\\s*\\)","message":"Use `laps.size()` for the number of laps and in the loops."},{"pattern":"\\blaps\\.get\\s*\\(","message":"Read the lap times from the list with `laps.get(i)`."}],"forbid":[]}]}