{"id":"objects-with-lists-totals","slug":"totals-from-the-list","title":"Totals from the objects on the list","text":"A class that holds a list of objects can answer questions about all of them together: how many pages the books have in all, how long they are on average, how many pages one author wrote. Each answer is a loop over the list:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        Bookshelf shelf = new Bookshelf(\"Study\");\n        shelf.add(new Book(\"Emma\", \"Austen\", 474));\n        shelf.add(new Book(\"Persuasion\", \"Austen\", 249));\n        shelf.add(new Book(\"Dracula\", \"Stoker\", 418));\n        shelf.add(new Book(\"Kindred\", \"Butler\", 264));\n        System.out.println(\"Pages: \" + shelf.totalPages());\n        System.out.println(\"Average: \" + shelf.averagePages());\n        System.out.println(\"By Austen: \" + shelf.pagesBy(\"Austen\"));\n        Bookshelf empty = new Bookshelf(\"Hallway\");\n        System.out.println(\"Pages: \" + empty.totalPages());\n        System.out.println(\"Average: \" + empty.averagePages());\n    }\n}\n// ==== Bookshelf.java ====\nimport java.util.ArrayList;\n\npublic class Bookshelf {\n    private String room;\n    private ArrayList<Book> books;\n\n    public Bookshelf(String room) {\n        this.room = room;\n        this.books = new ArrayList<>();\n    }\n\n    public void add(Book book) {\n        this.books.add(book);\n    }\n\n    public int totalPages() {\n        int total = 0;\n        for (Book book : this.books) {\n            total = total + book.getPages();\n        }\n        return total;\n    }\n\n    public double averagePages() {\n        if (this.books.isEmpty()) {\n            return 0;\n        }\n        return (double) this.totalPages() / this.books.size();\n    }\n\n    public int pagesBy(String author) {\n        int total = 0;\n        for (Book book : this.books) {\n            if (book.getAuthor().equals(author)) {\n                total = total + book.getPages();\n            }\n        }\n        return total;\n    }\n}\n// ==== Book.java ====\npublic class Book {\n    private String title;\n    private String author;\n    private int pages;\n\n    public Book(String title, String author, int pages) {\n        this.title = title;\n        this.author = author;\n        this.pages = pages;\n    }\n\n    public String getAuthor() {\n        return this.author;\n    }\n\n    public int getPages() {\n        return this.pages;\n    }\n}\n```\n\n```output\nPages: 1405\nAverage: 351.25\nBy Austen: 723\nPages: 0\nAverage: 0.0\n```\n\n- `totalPages` is the sum pattern you know, over the shelf's own list: a local variable starts at 0, and each book adds its pages to it.\n- `averagePages` doesn't write the loop again. It calls the object's own `totalPages()` with `this.` (module 18), and divides by the number of books. The `(double)` makes the division keep its decimals (module 4). Without it, `1405 / 4` would be `351`.\n- The empty check comes first. With no books, the division would be 0 divided by 0, which for a `double` gives `NaN`, \"not a number\". Returning 0 is the choice made here, and since the method returns a `double`, it comes out as `0.0`.\n- `pagesBy` is a total with a condition: only the books that match add their pages.\n\n### Counted when asked, not kept\n\nThe shelf could keep the total in an instance variable of its own, and add to it in `add`. But then every method that changes the list, such as one that removes books, would have to remember to change the total too, and one that forgets makes it wrong. Counting from the list each time can't go out of date: the list is always right, so the total is too.\n","task":"A trip is made of legs, and `Leg.java` is ready: a leg goes from one place to another, and `getKm()` returns its length in kilometers. In `Trip.java`, write the method `totalKm()`: it returns the length of the whole trip, the sum of its legs. A trip with no legs is 0 km. The check runs:\n\n```java\nTrip trip = new Trip();\ntrip.add(new Leg(\"Harbor\", \"Mill\", 12));\ntrip.add(new Leg(\"Mill\", \"Pine Hill\", 30));\ntrip.add(new Leg(\"Pine Hill\", \"Camp\", 8));\nSystem.out.println(trip.totalKm());\nSystem.out.println(new Trip().totalKm());\n```\n\nand expects:\n\n```\n50\n0\n```\n","kind":"code","seed":"// ==== Trip.java ====\nimport java.util.ArrayList;\n\npublic class Trip {\n    private ArrayList<Leg> legs;\n\n    public Trip() {\n        this.legs = new ArrayList<>();\n    }\n\n    public void add(Leg leg) {\n        this.legs.add(leg);\n    }\n\n    // Write the totalKm method here.\n}\n\n// ==== Leg.java ====\npublic class Leg {\n    private String from;\n    private String to;\n    private int km;\n\n    public Leg(String from, String to, int km) {\n        this.from = from;\n        this.to = to;\n        this.km = km;\n    }\n\n    public int getKm() {\n        return this.km;\n    }\n\n    public String toString() {\n        return this.from + \" to \" + this.to + \", \" + this.km + \" km\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Trip trip = new Trip();\n        trip.add(new Leg(\"Harbor\", \"Mill\", 12));\n        trip.add(new Leg(\"Mill\", \"Pine Hill\", 30));\n        trip.add(new Leg(\"Pine Hill\", \"Camp\", 8));\n        System.out.println(trip.totalKm());\n        System.out.println(new Trip().totalKm());\n    }\n}\n","solution":"// ==== Trip.java ====\nimport java.util.ArrayList;\n\npublic class Trip {\n    private ArrayList<Leg> legs;\n\n    public Trip() {\n        this.legs = new ArrayList<>();\n    }\n\n    public void add(Leg leg) {\n        this.legs.add(leg);\n    }\n\n    public int totalKm() {\n        int total = 0;\n        for (Leg leg : this.legs) {\n            total = total + leg.getKm();\n        }\n        return total;\n    }\n}\n\n// ==== Leg.java ====\npublic class Leg {\n    private String from;\n    private String to;\n    private int km;\n\n    public Leg(String from, String to, int km) {\n        this.from = from;\n        this.to = to;\n        this.km = km;\n    }\n\n    public int getKm() {\n        return this.km;\n    }\n\n    public String toString() {\n        return this.from + \" to \" + this.to + \", \" + this.km + \" km\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Trip trip = new Trip();\n        trip.add(new Leg(\"Harbor\", \"Mill\", 12));\n        trip.add(new Leg(\"Mill\", \"Pine Hill\", 30));\n        trip.add(new Leg(\"Pine Hill\", \"Camp\", 8));\n        System.out.println(trip.totalKm());\n        System.out.println(new Trip().totalKm());\n    }\n}\n","hints":["The method returns a whole number: `public int totalKm() {`. Start a local total at 0 before the loop.","In `for (Leg leg : this.legs)`, add each leg's length: `total = total + leg.getKm();`. Return the total after the loop."],"tests":[{"name":"Test 1","stdin":"","call":"Trip trip = new Trip();\ntrip.add(new Leg(\"Harbor\", \"Mill\", 12));\ntrip.add(new Leg(\"Mill\", \"Pine Hill\", 30));\ntrip.add(new Leg(\"Pine Hill\", \"Camp\", 8));\nSystem.out.println(trip.totalKm());\nSystem.out.println(new Trip().totalKm());\n","expect":"50\n0","hidden":false},{"name":"Test 2","stdin":"","call":"Trip trip = new Trip();\ntrip.add(new Leg(\"A\", \"B\", 140));\nSystem.out.println(trip.totalKm());\ntrip.add(new Leg(\"B\", \"A\", 140));\nSystem.out.println(trip.totalKm());\nSystem.out.println(trip.totalKm());\n","expect":"140\n280\n280","hidden":true},{"name":"Test 3","stdin":"","call":"Trip first = new Trip();\nTrip second = new Trip();\nfirst.add(new Leg(\"X\", \"Y\", 5));\nsecond.add(new Leg(\"Y\", \"Z\", 7));\nsecond.add(new Leg(\"Z\", \"W\", 9));\nSystem.out.println(first.totalKm() + \" \" + second.totalKm());\n","expect":"5 16","hidden":true}],"require":[{"pattern":"\\bpublic\\s+int\\s+totalKm\\s*\\(\\s*\\)","message":"Write the method as `public int totalKm()`."},{"pattern":"\\.getKm\\s*\\(\\s*\\)","message":"Ask each leg for its length with `getKm()`."}],"forbid":[],"more":[{"task":"`Squad.java` has a method `averageGoals()`, but it has two bugs. For a squad whose players scored 3 and 4 goals it returns `3.0`, not `3.5`, and for a squad with no players it crashes. Fix it, so it returns the average with its decimals, and 0 for a squad with no players. `Player.java` and `Main.java` are ready, and when the method is fixed the program prints:\n\n```\n3.5\n0.0\n```\n","kind":"code","seed":"// ==== Squad.java ====\nimport java.util.ArrayList;\n\npublic class Squad {\n    private ArrayList<Player> players;\n\n    public Squad() {\n        this.players = new ArrayList<>();\n    }\n\n    public void add(Player player) {\n        this.players.add(player);\n    }\n\n    public int totalGoals() {\n        int total = 0;\n        for (Player player : this.players) {\n            total = total + player.getGoals();\n        }\n        return total;\n    }\n\n    public double averageGoals() {\n        return this.totalGoals() / this.players.size();\n    }\n}\n\n// ==== Player.java ====\npublic class Player {\n    private String name;\n    private int goals;\n\n    public Player(String name, int goals) {\n        this.name = name;\n        this.goals = goals;\n    }\n\n    public int getGoals() {\n        return this.goals;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Squad squad = new Squad();\n        squad.add(new Player(\"Ana\", 3));\n        squad.add(new Player(\"Bo\", 4));\n        System.out.println(squad.averageGoals());\n        Squad empty = new Squad();\n        System.out.println(empty.averageGoals());\n    }\n}\n","solution":"// ==== Squad.java ====\nimport java.util.ArrayList;\n\npublic class Squad {\n    private ArrayList<Player> players;\n\n    public Squad() {\n        this.players = new ArrayList<>();\n    }\n\n    public void add(Player player) {\n        this.players.add(player);\n    }\n\n    public int totalGoals() {\n        int total = 0;\n        for (Player player : this.players) {\n            total = total + player.getGoals();\n        }\n        return total;\n    }\n\n    public double averageGoals() {\n        if (this.players.isEmpty()) {\n            return 0;\n        }\n        return (double) this.totalGoals() / this.players.size();\n    }\n}\n\n// ==== Player.java ====\npublic class Player {\n    private String name;\n    private int goals;\n\n    public Player(String name, int goals) {\n        this.name = name;\n        this.goals = goals;\n    }\n\n    public int getGoals() {\n        return this.goals;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Squad squad = new Squad();\n        squad.add(new Player(\"Ana\", 3));\n        squad.add(new Player(\"Bo\", 4));\n        System.out.println(squad.averageGoals());\n        Squad empty = new Squad();\n        System.out.println(empty.averageGoals());\n    }\n}\n","hints":["`this.totalGoals()` and `this.players.size()` are both `int` values, so the division drops the decimals before the result becomes a `double`. With no players, it divides by zero, and an `int` division by zero crashes.","Check `if (this.players.isEmpty()) { return 0; }` first. Then `return (double) this.totalGoals() / this.players.size();`: the cast turns the total into a `double` before the division, as in the lesson's `averagePages`."],"tests":[{"name":"The program","stdin":"","expect":"3.5\n0.0","hidden":false},{"name":"Test 2","stdin":"","call":"Squad squad = new Squad();\nsquad.add(new Player(\"Cy\", 1));\nsquad.add(new Player(\"Di\", 2));\nsquad.add(new Player(\"Ed\", 2));\nsquad.add(new Player(\"Fa\", 2));\nSystem.out.println(squad.averageGoals());\nsquad.add(new Player(\"Gu\", 3));\nSystem.out.println(squad.averageGoals());\n","expect":"1.75\n2.0","hidden":true},{"name":"Test 3","stdin":"","call":"Squad squad = new Squad();\nSystem.out.println(squad.averageGoals());\nsquad.add(new Player(\"Hu\", 7));\nSystem.out.println(squad.averageGoals() + \" \" + squad.totalGoals());\n","expect":"0.0\n7.0 7","hidden":true}],"require":[],"forbid":[]},{"task":"A workout is a list of exercises. `Exercise.java` is ready: an exercise has a name, a number of minutes, and the calories it burns in a minute, with the getters `getMinutes()` and `getCaloriesPerMinute()`. In `Workout.java`, write three methods:\n\n- `totalMinutes()` returns the minutes of all the exercises together.\n- `totalCalories()` returns the calories of all the exercises together. Each exercise burns its minutes times its calories per minute.\n- `averageMinutes()` returns the average length of an exercise as a `double`, or 0 for a workout with no exercises.\n\nThe check runs:\n\n```java\nWorkout workout = new Workout();\nworkout.add(new Exercise(\"rowing\", 20, 8));\nworkout.add(new Exercise(\"cycling\", 15, 7));\nworkout.add(new Exercise(\"stretching\", 10, 3));\nSystem.out.println(workout.totalMinutes());\nSystem.out.println(workout.totalCalories());\nSystem.out.println(workout.averageMinutes());\nSystem.out.println(new Workout().averageMinutes());\n```\n\nand expects:\n\n```\n45\n295\n15.0\n0.0\n```\n","kind":"code","seed":"// ==== Workout.java ====\nimport java.util.ArrayList;\n\npublic class Workout {\n    private ArrayList<Exercise> exercises;\n\n    public Workout() {\n        this.exercises = new ArrayList<>();\n    }\n\n    public void add(Exercise exercise) {\n        this.exercises.add(exercise);\n    }\n\n    // Write the methods totalMinutes, totalCalories and averageMinutes here.\n}\n\n// ==== Exercise.java ====\npublic class Exercise {\n    private String name;\n    private int minutes;\n    private int caloriesPerMinute;\n\n    public Exercise(String name, int minutes, int caloriesPerMinute) {\n        this.name = name;\n        this.minutes = minutes;\n        this.caloriesPerMinute = caloriesPerMinute;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public int getCaloriesPerMinute() {\n        return this.caloriesPerMinute;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Workout workout = new Workout();\n        workout.add(new Exercise(\"rowing\", 20, 8));\n        workout.add(new Exercise(\"cycling\", 15, 7));\n        workout.add(new Exercise(\"stretching\", 10, 3));\n        System.out.println(workout.totalMinutes());\n        System.out.println(workout.totalCalories());\n        System.out.println(workout.averageMinutes());\n        System.out.println(new Workout().averageMinutes());\n    }\n}\n","solution":"// ==== Workout.java ====\nimport java.util.ArrayList;\n\npublic class Workout {\n    private ArrayList<Exercise> exercises;\n\n    public Workout() {\n        this.exercises = new ArrayList<>();\n    }\n\n    public void add(Exercise exercise) {\n        this.exercises.add(exercise);\n    }\n\n    public int totalMinutes() {\n        int total = 0;\n        for (Exercise exercise : this.exercises) {\n            total = total + exercise.getMinutes();\n        }\n        return total;\n    }\n\n    public int totalCalories() {\n        int total = 0;\n        for (Exercise exercise : this.exercises) {\n            total = total + exercise.getMinutes() * exercise.getCaloriesPerMinute();\n        }\n        return total;\n    }\n\n    public double averageMinutes() {\n        if (this.exercises.isEmpty()) {\n            return 0;\n        }\n        return (double) this.totalMinutes() / this.exercises.size();\n    }\n}\n\n// ==== Exercise.java ====\npublic class Exercise {\n    private String name;\n    private int minutes;\n    private int caloriesPerMinute;\n\n    public Exercise(String name, int minutes, int caloriesPerMinute) {\n        this.name = name;\n        this.minutes = minutes;\n        this.caloriesPerMinute = caloriesPerMinute;\n    }\n\n    public int getMinutes() {\n        return this.minutes;\n    }\n\n    public int getCaloriesPerMinute() {\n        return this.caloriesPerMinute;\n    }\n\n    public String toString() {\n        return this.name + \", \" + this.minutes + \" min\";\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        Workout workout = new Workout();\n        workout.add(new Exercise(\"rowing\", 20, 8));\n        workout.add(new Exercise(\"cycling\", 15, 7));\n        workout.add(new Exercise(\"stretching\", 10, 3));\n        System.out.println(workout.totalMinutes());\n        System.out.println(workout.totalCalories());\n        System.out.println(workout.averageMinutes());\n        System.out.println(new Workout().averageMinutes());\n    }\n}\n","hints":["Both totals are loops over `this.exercises` that add to a local total. For the calories, add `exercise.getMinutes() * exercise.getCaloriesPerMinute()` in each round.","`averageMinutes` first returns 0 when `this.exercises.isEmpty()`. Otherwise it returns `(double) this.totalMinutes() / this.exercises.size();`: without the `(double)`, 25 / 2 would be 12."],"tests":[{"name":"Test 1","stdin":"","call":"Workout workout = new Workout();\nworkout.add(new Exercise(\"rowing\", 20, 8));\nworkout.add(new Exercise(\"cycling\", 15, 7));\nworkout.add(new Exercise(\"stretching\", 10, 3));\nSystem.out.println(workout.totalMinutes());\nSystem.out.println(workout.totalCalories());\nSystem.out.println(workout.averageMinutes());\nSystem.out.println(new Workout().averageMinutes());\n","expect":"45\n295\n15.0\n0.0","hidden":false},{"name":"Test 2","stdin":"","call":"Workout workout = new Workout();\nSystem.out.println(workout.totalMinutes() + \" \" + workout.totalCalories());\nworkout.add(new Exercise(\"running\", 25, 11));\nworkout.add(new Exercise(\"walking\", 10, 4));\nSystem.out.println(workout.totalMinutes() + \" \" + workout.totalCalories());\nSystem.out.println(workout.averageMinutes());\n","expect":"0 0\n35 315\n17.5","hidden":true},{"name":"Test 3","stdin":"","call":"Workout workout = new Workout();\nworkout.add(new Exercise(\"plank\", 1, 5));\nworkout.add(new Exercise(\"squats\", 2, 6));\nworkout.add(new Exercise(\"jumping\", 2, 10));\nSystem.out.println(workout.averageMinutes());\nSystem.out.println(workout.totalCalories());\n","expect":"1.6666666666666667\n37","hidden":true}],"require":[{"pattern":"\\bpublic\\s+int\\s+totalMinutes\\s*\\(\\s*\\)","message":"Write the method as `public int totalMinutes()`."},{"pattern":"\\bpublic\\s+int\\s+totalCalories\\s*\\(\\s*\\)","message":"Write the method as `public int totalCalories()`."},{"pattern":"\\bpublic\\s+double\\s+averageMinutes\\s*\\(\\s*\\)","message":"Write the method as `public double averageMinutes()`."}],"forbid":[]}]}