{"id":"objects-with-lists-review","slug":"lists-review","title":"Lists, a quick review","text":"Part 6 starts with a tool you've used since module 13, the list, and puts it somewhere new: inside an object. First, a quick look back at what you already know.\n\n### A list of Strings\n\n```java\nArrayList<String> stops = new ArrayList<>();\nstops.add(\"Harbor\");\nstops.add(\"Market\");\nstops.add(\"Old Town\");\nSystem.out.println(stops.size() + \" stops, the second is \" + stops.get(1));\nfor (String stop : stops) {\n    System.out.println(\"Next: \" + stop);\n}\n```\n\n```output\n3 stops, the second is Market\nNext: Harbor\nNext: Market\nNext: Old Town\n```\n\n- `ArrayList<String>` is a list of Strings, and `new ArrayList<>()` makes a new, empty one.\n- `add` puts a value at the end, `size()` tells how many values there are, and `get(1)` gives the value at index 1. Indexes start at 0.\n- The for-each loop goes through the values in order.\n\nModule 14 added more: `contains`, `indexOf`, `remove`, `isEmpty` and `clear`. A list of whole numbers is an `ArrayList<Integer>`.\n\n### A list of objects\n\nModule 19 put objects of your own classes on a list. The loop then gets one object at a time, and asks it for its values with its getters:\n\n```java\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Book> books = new ArrayList<>();\n        books.add(new Book(\"Emma\", 474));\n        books.add(new Book(\"Dracula\", 418));\n        books.add(new Book(\"Kindred\", 264));\n\n        int pages = 0;\n        for (Book book : books) {\n            System.out.println(book);\n            pages = pages + book.getPages();\n        }\n        System.out.println(\"In all: \" + pages + \" pages\");\n    }\n}\n// ==== Book.java ====\npublic class Book {\n    private String title;\n    private int pages;\n\n    public Book(String title, int pages) {\n        this.title = title;\n        this.pages = pages;\n    }\n\n    public String getTitle() {\n        return this.title;\n    }\n\n    public int getPages() {\n        return this.pages;\n    }\n\n    public String toString() {\n        return this.title + \", \" + this.pages + \" pages\";\n    }\n}\n```\n\n```output\nEmma, 474 pages\nDracula, 418 pages\nKindred, 264 pages\nIn all: 1156 pages\n```\n\n### Whose list is it?\n\nIn these programs, the list is a local variable of `main`. For one list, that's fine. Now picture a home with two bookshelves, one in the living room and one in the bedroom. `main` would need two lists, and two more variables for the rooms' names, and every method would take a list as a parameter: `printBooks(bedroom)`, `totalPages(livingRoom)`. Nothing ties a room's name to its list, and any line of the program could change any list.\n\nModule 21 had the answer to this kind of mess: an object looks after its own data. A list is data too, so it can be an instance variable of an object:\n\n```java\npublic class Bookshelf {\n    private String room;\n    private ArrayList<Book> books;\n\n    // a constructor, and methods that add books, print them, count them...\n}\n```\n\nEach Bookshelf then keeps its own room and its own books, and `main` only calls methods such as `shelf.add(book)`. The rest of this module builds classes like this one, a piece at a time. First, a warm-up with lists as you know them.\n","task":"`Runner.java` is ready: a runner has a name and a time in minutes, with the getters `getName()` and `getMinutes()`, and a toString that gives, for example, `Ada, 27 min`. In `Main.java`, write the method `printFaster(ArrayList<Runner> runners, int limit)`. It prints every runner whose time is less than `limit` minutes, one per line, in the order of the list. The check runs:\n\n```java\nArrayList<Runner> runners = new ArrayList<>();\nrunners.add(new Runner(\"Ada\", 27));\nrunners.add(new Runner(\"Bo\", 35));\nrunners.add(new Runner(\"Cy\", 22));\nprintFaster(runners, 30);\n```\n\nand expects:\n\n```\nAda, 27 min\nCy, 22 min\n```\n","kind":"code","seed":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Runner> runners = new ArrayList<>();\n        runners.add(new Runner(\"Ada\", 27));\n        runners.add(new Runner(\"Bo\", 35));\n        runners.add(new Runner(\"Cy\", 22));\n        printFaster(runners, 30);\n    }\n\n    // Write the printFaster method here.\n}\n\n// ==== Runner.java ====\npublic class Runner {\n    private String name;\n    private int minutes;\n\n    public Runner(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n","solution":"// ==== Main.java ====\nimport java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<Runner> runners = new ArrayList<>();\n        runners.add(new Runner(\"Ada\", 27));\n        runners.add(new Runner(\"Bo\", 35));\n        runners.add(new Runner(\"Cy\", 22));\n        printFaster(runners, 30);\n    }\n\n    public static void printFaster(ArrayList<Runner> runners, int limit) {\n        for (Runner runner : runners) {\n            if (runner.getMinutes() < limit) {\n                System.out.println(runner);\n            }\n        }\n    }\n}\n\n// ==== Runner.java ====\npublic class Runner {\n    private String name;\n    private int minutes;\n\n    public Runner(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n","hints":["The method starts `public static void printFaster(ArrayList<Runner> runners, int limit) {`. Inside it, go through the list with `for (Runner runner : runners) {`.","In the loop, `runner.getMinutes()` is this runner's time. When it's less than `limit`, print the runner: `System.out.println(runner);` uses Runner's toString."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<Runner> runners = new ArrayList<>();\nrunners.add(new Runner(\"Ada\", 27));\nrunners.add(new Runner(\"Bo\", 35));\nrunners.add(new Runner(\"Cy\", 22));\nprintFaster(runners, 30);\n","expect":"Ada, 27 min\nCy, 22 min","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<Runner> runners = new ArrayList<>();\nrunners.add(new Runner(\"Ada\", 27));\nrunners.add(new Runner(\"Bo\", 35));\nrunners.add(new Runner(\"Cy\", 22));\nprintFaster(runners, 27);\nSystem.out.println(\"--\");\nprintFaster(runners, 40);\n","expect":"Cy, 22 min\n--\nAda, 27 min\nBo, 35 min\nCy, 22 min","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<Runner> none = new ArrayList<>();\nprintFaster(none, 50);\nnone.add(new Runner(\"Dee\", 50));\nprintFaster(none, 50);\nnone.add(new Runner(\"Eli\", 49));\nprintFaster(none, 50);\nSystem.out.println(\"done\");\n","expect":"Eli, 49 min\ndone","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+void\\s+printFaster\\s*\\(\\s*ArrayList<Runner>\\s+\\w+\\s*,\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public static void printFaster(ArrayList<Runner> runners, int limit)`."},{"pattern":"\\.getMinutes\\s*\\(\\s*\\)","message":"Ask each runner for its time with `getMinutes()`."}],"forbid":[],"more":[{"task":"What does this program print? A list is an object, so a list variable holds a reference to it, just like a variable of your own classes (module 22).\n","kind":"predict","seed":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> monday = new ArrayList<>();\n        monday.add(\"swim\");\n        ArrayList<String> tuesday = monday;\n        tuesday.add(\"run\");\n        monday.add(\"yoga\");\n        ArrayList<String> friday = new ArrayList<>();\n        friday.add(\"swim\");\n        System.out.println(monday.size() + \" \" + tuesday.size() + \" \" + friday.size());\n        System.out.println(tuesday);\n        System.out.println(monday == tuesday);\n        System.out.println(monday == friday);\n    }\n}\n","solution":"import java.util.ArrayList;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> monday = new ArrayList<>();\n        monday.add(\"swim\");\n        ArrayList<String> tuesday = monday;\n        tuesday.add(\"run\");\n        monday.add(\"yoga\");\n        ArrayList<String> friday = new ArrayList<>();\n        friday.add(\"swim\");\n        System.out.println(monday.size() + \" \" + tuesday.size() + \" \" + friday.size());\n        System.out.println(tuesday);\n        System.out.println(monday == tuesday);\n        System.out.println(monday == friday);\n    }\n}\n","hints":["`ArrayList<String> tuesday = monday;` makes no new list. It copies the reference, so `monday` and `tuesday` refer to the one list, and all three `add` calls on them go to that list.","`friday` is a new list of its own, made with `new`. It holds only `swim`. `==` asks whether two variables refer to the same object."],"tests":[{"name":"Output","stdin":"","expect":"3 3 1\n[swim, run, yoga]\ntrue\nfalse","hidden":false}],"require":[],"forbid":[],"lines":["3 3 1","[swim, run, yoga]","true","false"]},{"task":"Read runners until an empty line. Each line has a name and a time in minutes, separated by a space, like `Ada 27`. Make a `Runner` of each line and add it to the list `runners`. `Runner.java` is the class from the first challenge.\n\nThen print how many runners there are, like `Runners: 3`, and after that every runner, starting from the last one read and ending with the first. For the input shown below, the program prints:\n\n```\nRunners: 3\nCy, 22 min\nBo, 35 min\nAda, 27 min\n```\n","kind":"code","seed":"// ==== Main.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<Runner> runners = new ArrayList<>();\n\n    }\n}\n\n// ==== Runner.java ====\npublic class Runner {\n    private String name;\n    private int minutes;\n\n    public Runner(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n","solution":"// ==== Main.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<Runner> runners = new ArrayList<>();\n        while (true) {\n            String line = scanner.nextLine();\n            if (line.isEmpty()) {\n                break;\n            }\n            String[] parts = line.split(\" \");\n            runners.add(new Runner(parts[0], Integer.valueOf(parts[1])));\n        }\n        System.out.println(\"Runners: \" + runners.size());\n        for (int i = runners.size() - 1; i >= 0; i--) {\n            System.out.println(runners.get(i));\n        }\n    }\n}\n\n// ==== Runner.java ====\npublic class Runner {\n    private String name;\n    private int minutes;\n\n    public Runner(String name, int minutes) {\n        this.name = name;\n        this.minutes = minutes;\n    }\n\n    public String getName() {\n        return this.name;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n","hints":["Read in a `while (true)` loop and `break` at the empty line. `line.split(\" \")` splits `Ada 27` into the name and the minutes, and `Integer.valueOf(parts[1])` turns the minutes into a number: `runners.add(new Runner(parts[0], Integer.valueOf(parts[1])));`","A for-each loop only goes forwards. To start from the last runner, loop over the indexes backwards: `for (int i = runners.size() - 1; i >= 0; i--)`, and print `runners.get(i)`."],"tests":[{"name":"Test 1","stdin":"Ada 27\nBo 35\nCy 22\n\n","expect":"Runners: 3\nCy, 22 min\nBo, 35 min\nAda, 27 min","hidden":false},{"name":"Test 2","stdin":"\n","expect":"Runners: 0","hidden":true},{"name":"Test 3","stdin":"Mo 41\n\n","expect":"Runners: 1\nMo, 41 min","hidden":true},{"name":"Test 4","stdin":"Kim 30\nLou 18\nMax 25\nNia 33\nOz 20\n\n","expect":"Runners: 5\nOz, 20 min\nNia, 33 min\nMax, 25 min\nLou, 18 min\nKim, 30 min","hidden":true}],"require":[],"forbid":[]}]}