{"id":"hash-maps-going-through","slug":"going-through","title":"Going through a hash map","text":"So far, every lookup started from a key. To do something with all the pairs, such as print them or add up the values, go through the map's keys. `keySet()` gives all the keys, and a for-each loop goes through them. `get` gives each key's value:\n\n```java\nHashMap<String, String> airports = new HashMap<>();\nairports.put(\"YVR\", \"Vancouver\");\nairports.put(\"HEL\", \"Helsinki\");\nairports.put(\"LIS\", \"Lisbon\");\nairports.put(\"CPT\", \"Cape Town\");\n\nfor (String code : airports.keySet()) {\n    System.out.println(code + \": \" + airports.get(code));\n}\n```\n\n```output\nYVR: Vancouver\nCPT: Cape Town\nLIS: Lisbon\nHEL: Helsinki\n```\n\nLook at the order. It isn't the order the codes were added in, and it isn't alphabetical either. A hash map keeps each key where its hash code sends it, and the loop goes through the keys in that order. With these four String keys, the order happens to be the same every time the program runs. But Java makes no promise about it: other keys, or more of them, can come out in a completely different order. **Never write a program that depends on the order of a HashMap.** (Printing a whole map, `System.out.println(airports)`, shows its pairs as `{YVR=Vancouver, CPT=Cape Town, ...}`, in the same order.)\n\n### The values\n\nWhen the keys don't matter, `values()` gives just the values. The order of the values is the map's order again, but a total doesn't depend on order:\n\n```java\nHashMap<String, Integer> jars = new HashMap<>();\njars.put(\"marmalade\", 3);\njars.put(\"plum jam\", 5);\njars.put(\"pickles\", 1);\n\nint total = 0;\nfor (int count : jars.values()) {\n    total += count;\n}\nSystem.out.println(\"Jars in all: \" + total);\n```\n\n```output\nJars in all: 9\n```\n\n### In an order you choose\n\nTo print the pairs in a fixed order, copy the keys into a list, and sort the list with `Collections.sort` (module 28). Then go through the list, and get each value from the map:\n\n```java\nHashMap<String, String> airports = new HashMap<>();\nairports.put(\"YVR\", \"Vancouver\");\nairports.put(\"HEL\", \"Helsinki\");\nairports.put(\"LIS\", \"Lisbon\");\nairports.put(\"CPT\", \"Cape Town\");\n\nArrayList<String> codes = new ArrayList<>(airports.keySet());\nCollections.sort(codes);\nfor (String code : codes) {\n    System.out.println(code + \": \" + airports.get(code));\n}\n```\n\n```output\nCPT: Cape Town\nHEL: Helsinki\nLIS: Lisbon\nYVR: Vancouver\n```\n\n- `new ArrayList<>(...)` makes a new list with the same values (module 14), and it works with a key set too. A loop that adds each key to an empty list does the same.\n- Sorting the list changes only the list. The map stays as it was.\n- Java also has maps that keep an order of their own: `TreeMap` keeps its keys sorted, and `LinkedHashMap` keeps the order they were added in. This course uses `HashMap`, and sorts the keys whenever the order matters.\n\n### Picking some of the pairs\n\nTo pick pairs by their values, go through the keys and check each value. Collect the keys you want in a list, and sort it before printing. Here the pantry makes a shopping list of the foods with fewer than 2 jars left:\n\n```java\nHashMap<String, Integer> jars = new HashMap<>();\njars.put(\"marmalade\", 3);\njars.put(\"plum jam\", 1);\njars.put(\"pickles\", 1);\njars.put(\"mustard\", 4);\n\nArrayList<String> toBuy = new ArrayList<>();\nfor (String food : jars.keySet()) {\n    if (jars.get(food) < 2) {\n        toBuy.add(food);\n    }\n}\nCollections.sort(toBuy);\nSystem.out.println(\"To buy: \" + toBuy);\n```\n\n```output\nTo buy: [pickles, plum jam]\n```\n\nAs with a list (module 14), don't add or remove keys while a for-each goes through the same map. To remove pairs, collect their keys in a list first, and remove them after the loop.\n","task":"Fill in the blanks of `printAirports`, which prints every code and city of the map, one per line, in the alphabetical order of the codes. The check runs:\n\n```java\nHashMap<String, String> airports = new HashMap<>();\nairports.put(\"SYD\", \"Sydney\");\nairports.put(\"AKL\", \"Auckland\");\nairports.put(\"DXB\", \"Dubai\");\nairports.put(\"KEF\", \"Reykjavik\");\nprintAirports(airports);\n```\n\nand expects:\n\n```\nAKL Auckland\nDXB Dubai\nKEF Reykjavik\nSYD Sydney\n```\n","kind":"fill","seed":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<String, String> airports = new HashMap<>();\n        airports.put(\"SYD\", \"Sydney\");\n        airports.put(\"AKL\", \"Auckland\");\n        airports.put(\"DXB\", \"Dubai\");\n        airports.put(\"KEF\", \"Reykjavik\");\n        printAirports(airports);\n    }\n\n    public static void printAirports(HashMap<String, String> airports) {\n        ArrayList<String> codes = new ArrayList<>(airports.[[keySet]]());\n        Collections.[[sort]](codes);\n        for (String code : codes) {\n            System.out.println(code + \" \" + airports.[[get]](code));\n        }\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<String, String> airports = new HashMap<>();\n        airports.put(\"SYD\", \"Sydney\");\n        airports.put(\"AKL\", \"Auckland\");\n        airports.put(\"DXB\", \"Dubai\");\n        airports.put(\"KEF\", \"Reykjavik\");\n        printAirports(airports);\n    }\n\n    public static void printAirports(HashMap<String, String> airports) {\n        ArrayList<String> codes = new ArrayList<>(airports.keySet());\n        Collections.sort(codes);\n        for (String code : codes) {\n            System.out.println(code + \" \" + airports.get(code));\n        }\n    }\n}\n","hints":["The list is a copy of the map's keys, which `keySet()` gives. `Collections.sort` then puts the codes in alphabetical order.","The loop goes through the sorted codes, and each city comes from the map: `airports.get(code)`."],"tests":[{"name":"Test 1","stdin":"","call":"HashMap<String, String> airports = new HashMap<>();\nairports.put(\"SYD\", \"Sydney\");\nairports.put(\"AKL\", \"Auckland\");\nairports.put(\"DXB\", \"Dubai\");\nairports.put(\"KEF\", \"Reykjavik\");\nprintAirports(airports);\n","expect":"AKL Auckland\nDXB Dubai\nKEF Reykjavik\nSYD Sydney","hidden":false},{"name":"Test 2","stdin":"","call":"HashMap<String, String> airports = new HashMap<>();\nairports.put(\"YVR\", \"Vancouver\");\nairports.put(\"HEL\", \"Helsinki\");\nairports.put(\"LIS\", \"Lisbon\");\nairports.put(\"NBO\", \"Nairobi\");\nairports.put(\"CPT\", \"Cape Town\");\nprintAirports(airports);\nSystem.out.println(airports.size());\n","expect":"CPT Cape Town\nHEL Helsinki\nLIS Lisbon\nNBO Nairobi\nYVR Vancouver\n5","hidden":true},{"name":"Test 3","stdin":"","call":"HashMap<String, String> airports = new HashMap<>();\nairports.put(\"ICN\", \"Seoul\");\nprintAirports(airports);\nprintAirports(new HashMap<>());\nSystem.out.println(\"done\");\n","expect":"ICN Seoul\ndone","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A museum's audio guide keeps how many times each stop was played, with the stop numbers as keys. What does this program print? One stop is put twice.\n","kind":"predict","seed":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Integer, Integer> listens = new HashMap<>();\n        listens.put(12, 40);\n        listens.put(27, 15);\n        listens.put(31, 8);\n        listens.put(12, 25);\n\n        int total = 0;\n        for (int count : listens.values()) {\n            total += count;\n        }\n        int popular = 0;\n        for (int stop : listens.keySet()) {\n            if (listens.get(stop) >= 15) {\n                popular++;\n            }\n        }\n        System.out.println(total);\n        System.out.println(popular);\n        System.out.println(listens.size());\n    }\n}\n","solution":"import java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<Integer, Integer> listens = new HashMap<>();\n        listens.put(12, 40);\n        listens.put(27, 15);\n        listens.put(31, 8);\n        listens.put(12, 25);\n\n        int total = 0;\n        for (int count : listens.values()) {\n            total += count;\n        }\n        int popular = 0;\n        for (int stop : listens.keySet()) {\n            if (listens.get(stop) >= 15) {\n                popular++;\n            }\n        }\n        System.out.println(total);\n        System.out.println(popular);\n        System.out.println(listens.size());\n    }\n}\n","hints":["The second `put` for stop 12 replaces 40 with 25, so the map has three pairs, with the values 25, 15 and 8. The first loop adds them up.","The second loop counts the stops whose value is at least 15. The order the loops go in doesn't matter for a total or a count."],"tests":[{"name":"Output","stdin":"","expect":"48\n2\n3","hidden":false}],"require":[],"forbid":[],"lines":["48","2","3"]},{"task":"A radio station keeps how many times each song was played this week, in a `HashMap<String, Integer>` with the titles as keys. Write the method `printReport(HashMap<String, Integer> plays, int atLeast)`. It prints each song that was played at least `atLeast` times, as the title, `: ` and the number of plays, in the alphabetical order of the titles. Then it prints `Plays in all: ` and the plays of all the songs added up, the ones not printed too. The check runs:\n\n```java\nHashMap<String, Integer> plays = new HashMap<>();\nplays.put(\"Night Bus\", 7);\nplays.put(\"Slow River\", 2);\nplays.put(\"Paper Lanterns\", 5);\nplays.put(\"Blue Tuesday\", 9);\nprintReport(plays, 5);\n```\n\nand expects:\n\n```\nBlue Tuesday: 9\nNight Bus: 7\nPaper Lanterns: 5\nPlays in all: 23\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<String, Integer> plays = new HashMap<>();\n        plays.put(\"Night Bus\", 7);\n        plays.put(\"Slow River\", 2);\n        plays.put(\"Paper Lanterns\", 5);\n        plays.put(\"Blue Tuesday\", 9);\n        printReport(plays, 5);\n    }\n\n    // Write the method printReport here.\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\n\npublic class Main {\n    public static void main(String[] args) {\n        HashMap<String, Integer> plays = new HashMap<>();\n        plays.put(\"Night Bus\", 7);\n        plays.put(\"Slow River\", 2);\n        plays.put(\"Paper Lanterns\", 5);\n        plays.put(\"Blue Tuesday\", 9);\n        printReport(plays, 5);\n    }\n\n    public static void printReport(HashMap<String, Integer> plays, int atLeast) {\n        ArrayList<String> titles = new ArrayList<>();\n        int total = 0;\n        for (String title : plays.keySet()) {\n            total += plays.get(title);\n            if (plays.get(title) >= atLeast) {\n                titles.add(title);\n            }\n        }\n        Collections.sort(titles);\n        for (String title : titles) {\n            System.out.println(title + \": \" + plays.get(title));\n        }\n        System.out.println(\"Plays in all: \" + total);\n    }\n}\n","hints":["Go through `plays.keySet()`. Add every song's plays to a total, and add the titles with at least `atLeast` plays to a list.","A HashMap's own order isn't alphabetical, so sort the list with `Collections.sort` before printing it. Print the total after the list."],"tests":[{"name":"Test 1","stdin":"","call":"HashMap<String, Integer> plays = new HashMap<>();\nplays.put(\"Night Bus\", 7);\nplays.put(\"Slow River\", 2);\nplays.put(\"Paper Lanterns\", 5);\nplays.put(\"Blue Tuesday\", 9);\nprintReport(plays, 5);\n","expect":"Blue Tuesday: 9\nNight Bus: 7\nPaper Lanterns: 5\nPlays in all: 23","hidden":false},{"name":"Test 2","stdin":"","call":"HashMap<String, Integer> plays = new HashMap<>();\nplays.put(\"Cedar Smoke\", 3);\nplays.put(\"Harbor Lights\", 12);\nplays.put(\"Wild Thyme\", 3);\nplays.put(\"Copper Sky\", 1);\nplays.put(\"Afterglow\", 8);\nplays.put(\"Morning Ferry\", 4);\nprintReport(plays, 3);\nSystem.out.println(\"--\");\nprintReport(plays, 20);\n","expect":"Afterglow: 8\nCedar Smoke: 3\nHarbor Lights: 12\nMorning Ferry: 4\nWild Thyme: 3\nPlays in all: 31\n--\nPlays in all: 31","hidden":true},{"name":"Test 3","stdin":"","call":"HashMap<String, Integer> plays = new HashMap<>();\nprintReport(plays, 1);\nplays.put(\"Lone Star Motel\", 2);\nplays.put(\"Echo Park\", 0);\nprintReport(plays, 0);\n","expect":"Plays in all: 0\nEcho Park: 0\nLone Star Motel: 2\nPlays in all: 2","hidden":true}],"require":[{"pattern":"\\bpublic\\s+static\\s+void\\s+printReport\\s*\\(\\s*HashMap<String,\\s*Integer>\\s+\\w+\\s*,\\s*int\\s+\\w+\\s*\\)","message":"Write the method as `public static void printReport(HashMap<String, Integer> plays, int atLeast)`."},{"pattern":"\\bsort\\s*\\(","message":"Sort the titles, so that they're printed in alphabetical order. A HashMap's own order can't be relied on."}],"forbid":[]}]}