Java Arena
Step 3 of 4

Groups inside a class

So far, the map of lists was passed to methods as a parameter. In a real program it usually lives inside a class, as an instance variable, the way module 24 kept a list inside an object. The class's methods are then the only way to change it. The rest of the program says what it wants done, like register.join("Debate", "Amira"), and doesn't need to know that there's a map of lists inside.

Here's a register of the school's clubs. Main is a test drive:

Main.java
public class Main {
    public static void main(String[] args) {
        ClubRegister register = new ClubRegister();
        register.join("Robotics", "Priya");
        register.join("Debate", "Amira");
        register.join("Debate", "Jonas");
        register.join("Art", "Leo");
        System.out.println(register.clubNames());
        System.out.println(register.members("Debate"));

        register.leave("Debate", "Amira");
        register.leave("Art", "Leo");
        System.out.println(register.members("Debate"));
        System.out.println(register.clubNames());
        System.out.println(register.members("Art"));
    }
}
ClubRegister.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;

public class ClubRegister {
    private HashMap<String, ArrayList<String>> clubs;

    public ClubRegister() {
        this.clubs = new HashMap<>();
    }

    public void join(String club, String student) {
        if (!this.clubs.containsKey(club)) {
            this.clubs.put(club, new ArrayList<>());
        }
        this.clubs.get(club).add(student);
    }

    public ArrayList<String> members(String club) {
        return this.clubs.getOrDefault(club, new ArrayList<>());
    }

    public void leave(String club, String student) {
        if (this.clubs.containsKey(club)) {
            ArrayList<String> members = this.clubs.get(club);
            members.remove(student);
            if (members.isEmpty()) {
                this.clubs.remove(club);
            }
        }
    }

    public ArrayList<String> clubNames() {
        ArrayList<String> names = new ArrayList<>(this.clubs.keySet());
        Collections.sort(names);
        return names;
    }
}
Output
[Art, Debate, Robotics]
[Amira, Jonas]
[Jonas]
[Debate, Robotics]
[]
  • The constructor creates the map. Without that line, this.clubs would be null, and the first join would crash (module 22).
  • join and members are step 1's join and membersOf, with this.clubs in place of a parameter.
  • leave uses the list's remove(student), which removes the first copy of the student and does nothing if the student isn't there (module 14). When the last member leaves, this.clubs.remove(club) takes the club out of the map too. Without that, a club with an empty list would stay in the map, and in clubNames, forever.
  • clubNames returns a new, sorted list of the keys. It's a list of its own: sorting it, or anything the caller does with it, doesn't change the map. The names come out in alphabetical order whatever order the map keeps its keys in.
  • ClubRegister prints nothing. Its methods return their answers, and Main decides what to print.

One thing to be aware of: members returns the list that's in the map, so code outside the class could change it, for example with register.members("Debate").clear(). A class that wants to guard its data can return a copy instead: new ArrayList<>(list) makes a new list with the same elements as list.

Your task

Challenge 1 of 3

A restaurant keeps the dishes that each table has ordered. Tables have numbers, so the keys are Integers: HashMap<Integer, ArrayList<String>>. In TableOrders.java, write:

  • the constructor, which creates the map,
  • add(int table, String dish), which adds the dish to the table's list, and creates the list for the table's first dish,
  • dishesAt(int table), which returns the table's list of dishes, or an empty list for a table with no orders,
  • tables(), which returns a new list of the table numbers that have orders, from the smallest to the largest.

Main.java is a test drive, and it prints:

[3, 12, 21]
[soup, salad]
[]

Challenge 2

A garden keeps the plants of each bed, and plantsIn returns the list that's in the map, as ClubRegister's members does. What does this program print?

Challenge 3

The restaurant needs two more methods in TableOrders. The class from the first task is ready. Add:

  • countOf(String dish), which returns how many of that dish have been ordered at all the tables together.
  • tablesWith(String dish), which returns a new list of the tables that have ordered the dish, from the smallest number to the largest. A table that ordered the dish more than once is on the list once.

Main.java is a test drive, and it prints:

4
[3, 12, 21]
[3] []