{"id":"strings-processing-lines","slug":"processing-many-lines","title":"Processing many lines","text":"Real data comes in many lines. The `while (true)` loop from module 8, which reads until a signal to stop, works here too. This time the signal is an empty line, and each line before it is split and used:\n\n```java\nimport java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int total = 0;\n        int highest = 0;\n        String priciest = \"\";\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\",\");\n            int price = Integer.valueOf(parts[1]);\n            total += price;\n            if (price > highest) {\n                highest = price;\n                priciest = parts[0];\n            }\n        }\n        System.out.println(\"Total: \" + total);\n        System.out.println(\"Most expensive: \" + priciest + \" (\" + highest + \")\");\n    }\n}\n```\n\n```input\nbread,3\ncheese,7\nmilk,2\n\n```\n\n```output\nTotal: 12\nMost expensive: cheese (7)\n```\n\n- `line.isEmpty()` is true for the empty line at the end of the input, where the user pressed Enter without typing anything, and `break` ends the loop. `line.equals(\"\")` does the same, but `line == \"\"` isn't reliable, for the reasons in the step on comparing.\n- The total and the highest price are updated in every round. Each line is used once and then forgotten, so the program needs no list.\n- To know which product was the most expensive, its name is kept in a variable of its own, updated together with the price.\n\nStarting `highest` at 0 works because prices are never negative. For values that can be below zero, such as temperatures, start from a number that no real value can beat, or from the first line's value.\n\n### Other ways to stop\n\nThe signal to stop can be anything the data never contains. Instead of an empty line, it's often a word such as `end`, checked with `line.equals(\"end\")`.\n\nWhen the lines are already in an array, there's nothing to read and no signal to wait for: a for-each loop goes through the lines, and its body is the same as above.\n\n```java\nfor (String line : lines) {\n    String[] parts = line.split(\",\");\n    int price = Integer.valueOf(parts[1]);\n    // ... the same as in the while loop\n}\n```\n","task":"Read lines in the form `runner,minutes` until the line `end`. Then print how many runners there were, how many of them finished in under an hour (less than 60 minutes), and their average time as a decimal number. For the input `Aino,42`, `Bruno,65`, `Chen,49` and `end` the program prints:\n\n```\nRunners: 3\nUnder an hour: 2\nAverage: 52.0\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\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 count = 0;\n        int underHour = 0;\n        int sum = 0;\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            String[] parts = line.split(\",\");\n            int minutes = Integer.valueOf(parts[1]);\n            sum += minutes;\n            count++;\n            if (minutes < 60) {\n                underHour++;\n            }\n        }\n        System.out.println(\"Runners: \" + count);\n        System.out.println(\"Under an hour: \" + underHour);\n        System.out.println(\"Average: \" + (double) sum / count);\n    }\n}\n","hints":["Before the loop, three counters start at 0: all runners, runners under an hour, and the sum of the times. In the loop, stop at `end`; otherwise split the line and turn `parts[1]` into a number.","Add the minutes to the sum and count the runner; if the minutes are less than 60, count them in the second counter too.","After the loop, `(double) sum / count` keeps the decimals."],"tests":[{"name":"Test 1","stdin":"Aino,42\nBruno,65\nChen,49\nend\n","expect":"Runners: 3\nUnder an hour: 2\nAverage: 52.0","hidden":false},{"name":"Test 2","stdin":"Dana,50\nend\n","expect":"Runners: 1\nUnder an hour: 1\nAverage: 50.0","hidden":true},{"name":"Test 3","stdin":"Eero,70\nFay,61\nend\n","expect":"Runners: 2\nUnder an hour: 0\nAverage: 65.5","hidden":true},{"name":"Test 4","stdin":"Gus,40\nHana,60\nIlse,59\nJuno,75\nend\n","expect":"Runners: 4\nUnder an hour: 2\nAverage: 58.5","hidden":true}],"require":[{"pattern":"\\.split\\s*\\(","message":"Cut each line into its parts with `split`."}],"forbid":[{"pattern":"(==|!=)\\s*\"\"|\"\"\\s*(==|!=)","message":"Check for `end` with `equals`, not `==`."}],"more":[{"task":"Write a method `coldest(String[] lines)` that gets lines in the form `city,temperature` and returns the coldest city with its temperature in parentheses. The temperatures are whole numbers, and some can be below zero. The check runs this and expects the output below:\n\n```java\nString[] lines = {\"Lisbon,14\", \"Oslo,-3\", \"Rome,11\"};\nSystem.out.println(coldest(lines));\n```\n\n```\nOslo (-3)\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        String[] lines = {\"Lisbon,14\", \"Oslo,-3\", \"Rome,11\"};\n        System.out.println(coldest(lines));\n    }\n\n    // Write the coldest method here.\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        String[] lines = {\"Lisbon,14\", \"Oslo,-3\", \"Rome,11\"};\n        System.out.println(coldest(lines));\n    }\n\n    public static String coldest(String[] lines) {\n        int lowest = 1000;\n        String city = \"\";\n        for (String line : lines) {\n            String[] parts = line.split(\",\");\n            int temperature = Integer.valueOf(parts[1]);\n            if (temperature < lowest) {\n                lowest = temperature;\n                city = parts[0];\n            }\n        }\n        return city + \" (\" + lowest + \")\";\n    }\n}\n","hints":["Keep the lowest temperature so far, and its city, in two variables. Start the temperature from a number no city will beat, such as 1000, so the first line always replaces it.","For each line: split it, and `if (temperature < lowest) { lowest = temperature; city = parts[0]; }`. After the loop, return `city + \" (\" + lowest + \")\"`."],"tests":[{"name":"Test 1","stdin":"","call":"String[] lines = {\"Lisbon,14\", \"Oslo,-3\", \"Rome,11\"};\nSystem.out.println(coldest(lines));\n","expect":"Oslo (-3)","hidden":false},{"name":"Test 2","stdin":"","call":"String[] lines = {\"Nuuk,-12\", \"Reykjavik,-2\", \"Tromso,-15\"};\nSystem.out.println(coldest(lines));\n","expect":"Tromso (-15)","hidden":true},{"name":"Test 3","stdin":"","call":"String[] lines = {\"Cairo,25\"};\nSystem.out.println(coldest(lines));\n","expect":"Cairo (25)","hidden":true},{"name":"Test 4","stdin":"","call":"String[] lines = {\"Madrid,5\", \"Paris,5\", \"Berlin,3\", \"Vienna,4\"};\nSystem.out.println(coldest(lines));\n","expect":"Berlin (3)","hidden":true}],"require":[{"pattern":"\\.split\\s*\\(","message":"Cut each line into its parts with `split`."}],"forbid":[]},{"task":"Read an order, one line per item in the form `item,price,count`, until the line `end`. For each item, print its name, the count and what that line costs. At the end, print the total of the whole order. For the input `pen,2,3`, `notebook,4,2`, `bag,15,1` and `end` the program prints:\n\n```\npen x3 = 6\nnotebook x2 = 8\nbag x1 = 15\nTotal: 29\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\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 total = 0;\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.equals(\"end\")) {\n                break;\n            }\n            String[] parts = line.split(\",\");\n            int price = Integer.valueOf(parts[1]);\n            int count = Integer.valueOf(parts[2]);\n            int cost = price * count;\n            System.out.println(parts[0] + \" x\" + count + \" = \" + cost);\n            total += cost;\n        }\n        System.out.println(\"Total: \" + total);\n    }\n}\n","hints":["Each line has three parts: `parts[0]` is the item, `parts[1]` the price and `parts[2]` the count. Turn the last two into numbers.","Print each item's line inside the loop, add its cost to `total`, and print the total after the loop."],"tests":[{"name":"Test 1","stdin":"pen,2,3\nnotebook,4,2\nbag,15,1\nend\n","expect":"pen x3 = 6\nnotebook x2 = 8\nbag x1 = 15\nTotal: 29","hidden":false},{"name":"Test 2","stdin":"stamp,1,10\nend\n","expect":"stamp x10 = 10\nTotal: 10","hidden":true},{"name":"Test 3","stdin":"mug,8,2\nplate,6,4\nend\n","expect":"mug x2 = 16\nplate x4 = 24\nTotal: 40","hidden":true}],"require":[{"pattern":"\\.split\\s*\\(","message":"Cut each line into its parts with `split`."}],"forbid":[{"pattern":"(==|!=)\\s*\"\"|\"\"\\s*(==|!=)","message":"Check for `end` with `equals`, not `==`."}]}]}