{"id":"list-and-map-internals-collisions-and-growing","slug":"collisions-and-growing","title":"Collisions, updates, removing and growing","text":"The map from step 6 can put and get. This step makes it a map you could really use: one that handles keys that share a bucket, gives each key only one value, removes keys, and grows as it fills up.\n\n### Two keys, one bucket\n\nIn step 6, Amara and Elif both went to bucket 4. Their hash codes are different, 63372932 and 2162724, but the remainders after dividing by 8 are the same. Two different keys can even have the very same hash code: module 32 showed that `\"Aa\"` and `\"BB\"` both have 2112. When two keys land in one bucket, that's called a **collision**.\n\nCollisions are why each bucket is a list and not a single place. A collision costs no data: both pairs are in the bucket, and `get` compares the keys with `equals` to find the right one. It only costs time, since `get` may have to look at more than one pair.\n\n### The same key twice\n\nStep 6's `put` always adds a new pair. Put Bo's extension in again, as 109, and bucket 5 ends up with two pairs for Bo: `size()` says 6 for five people, and `get(\"Bo\")` still finds the old pair first and returns 102. A map has one value per key, and a new `put` replaces the old value (module 31).\n\nSo `put` looks for the key in its bucket first. If it's there, the pair gets the new value, with KeyValue's `setValue`, and that's all. Only a new key adds a pair and grows the size:\n\n```java\npublic void put(K key, V value) {\n    ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n    for (KeyValue<K, V> pair : bucket) {\n        if (pair.getKey().equals(key)) {\n            pair.setValue(value);\n            return;\n        }\n    }\n    bucket.add(new KeyValue<>(key, value));\n    this.size++;\n}\n```\n\n### Removing a key\n\n`remove` finds the key's pair in its bucket, takes it out of the bucket, and returns its value, or `null` when the key isn't there, as HashMap's `remove` does:\n\n```java\npublic V remove(K key) {\n    ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n    for (int i = 0; i < bucket.size(); i++) {\n        if (bucket.get(i).getKey().equals(key)) {\n            this.size--;\n            return bucket.remove(i).getValue();\n        }\n    }\n    return null;\n}\n```\n\n- The loop goes by index, so that `bucket.remove(i)` can remove the pair at that index. It returns the removed pair, and `getValue()` gives its value.\n- The bucket's own `remove` moves the pairs after the removed one, as in step 4. A bucket holds only a few pairs, so that's quick.\n\n### Growing\n\nThe map has 8 buckets. With 800 keys in it, each bucket would hold about 100 pairs, and `get` would compare with up to 100 keys: a linear search again, only a bit shorter. A map stays fast only while its buckets stay short, so it adds buckets as it fills up.\n\nThe rule here: when the map has more than 0.75 pairs per bucket, that is when `size > 0.75 * buckets.length`, the array of buckets becomes twice as long. Java's HashMap uses the same limit, 0.75, unless you give it another one, and it doubles its buckets too.\n\nGrowing can't just copy bucket 5 to bucket 5 of the new array. A key's bucket depends on the number of buckets: Bo's hash code is 2157, and 2157 % 8 is 5, but 2157 % 16 is 13. After growing, `get(\"Bo\")` looks in bucket 13, so Bo's pair must be there. So every pair is put again, into the bucket its hash code picks in the new array:\n\n```java\n@SuppressWarnings(\"unchecked\")\nprivate void grow() {\n    ArrayList<KeyValue<K, V>>[] old = this.buckets;\n    this.buckets = new ArrayList[old.length * 2];\n    for (int i = 0; i < this.buckets.length; i++) {\n        this.buckets[i] = new ArrayList<>();\n    }\n    for (ArrayList<KeyValue<K, V>> bucket : old) {\n        for (KeyValue<K, V> pair : bucket) {\n            bucketFor(pair.getKey()).add(pair);\n        }\n    }\n}\n```\n\n- `old` keeps the old array while `this.buckets` gets the new one, with an empty list in each place.\n- `bucketFor` divides by `this.buckets.length`, which is now 16, so it picks the bucket in the new array.\n- The pairs themselves move, not copies of them, and the size stays the same.\n\nLike the list's `grow`, this takes time, one step for each pair. But it doubles the buckets each time, so it happens rarely, and `put` stays fast on average.\n\n### The whole map at work\n\nHere's the map with all of this, counting the words of a short poem. `bucketCount()` is there only to watch the map grow:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        String[] poem = {\n            \"the rain on the roof\",\n            \"the rain in the street\",\n            \"a song for the rain\",\n            \"and a song for the feet\"\n        };\n        SimpleMap<String, Integer> counts = new SimpleMap<>();\n        for (String line : poem) {\n            for (String word : line.split(\" \")) {\n                Integer count = counts.get(word);\n                if (count == null) {\n                    counts.put(word, 1);\n                } else {\n                    counts.put(word, count + 1);\n                }\n            }\n        }\n        System.out.println(counts.size() + \" different words in \" + counts.bucketCount() + \" buckets\");\n        String[] wanted = {\"the\", \"rain\", \"song\", \"feet\", \"sun\"};\n        for (String word : wanted) {\n            System.out.println(word + \": \" + counts.get(word));\n        }\n        System.out.println(\"removed the: \" + counts.remove(\"the\") + \", \" + counts.size() + \" words left\");\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                pair.setValue(value);\n                return;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        if (this.size > 0.75 * this.buckets.length) {\n            grow();\n        }\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public V remove(K key) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (int i = 0; i < bucket.size(); i++) {\n            if (bucket.get(i).getKey().equals(key)) {\n                this.size--;\n                return bucket.remove(i).getValue();\n            }\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void grow() {\n        ArrayList<KeyValue<K, V>>[] old = this.buckets;\n        this.buckets = new ArrayList[old.length * 2];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        for (ArrayList<KeyValue<K, V>> bucket : old) {\n            for (KeyValue<K, V> pair : bucket) {\n                bucketFor(pair.getKey()).add(pair);\n            }\n        }\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public int bucketCount() {\n        return this.buckets.length;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n```\n\n```output\n11 different words in 16 buckets\nthe: 6\nrain: 3\nsong: 2\nfeet: 1\nsun: null\nremoved the: 6, 10 words left\n```\n\n- The poem has 21 words, but 11 different ones. Each word after the first time only changes its count, so the size counts each word once.\n- The seventh new word took the size to 7, more than 0.75 * 8 = 6, and the map grew to 16 buckets. With 11 words it's still below 0.75 * 16 = 12.\n- `counts.get(word)` returns an Integer, which is `null` for a word not counted yet. That's why `count` is an `Integer`, not an `int`.\n","task":"A parking office keeps its permits in a SimpleMap, from a car's plate to the holder's name. Java's HashMap's `put` returns the value the key had before, or `null` for a new key, so a program can tell a renewal from a new permit. `SimpleMap.java` has step 6's `put`, which returns nothing. Rewrite it to return a `V`:\n\n- when the key is in its bucket already, give its pair the new value, and return the old one\n- otherwise, add a new pair, count it, and return `null`\n\nThe check runs:\n\n```java\nSimpleMap<String, String> permits = new SimpleMap<>();\nSystem.out.println(permits.put(\"KX-482\", \"Ines\"));\nSystem.out.println(permits.put(\"BT-907\", \"Theo\"));\nSystem.out.println(permits.put(\"KX-482\", \"Rafael\"));\nSystem.out.println(permits.get(\"KX-482\") + \", \" + permits.size() + \" permits\");\n```\n\nand expects:\n\n```\nnull\nnull\nInes\nRafael, 2 permits\n```\n","kind":"code","seed":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        bucketFor(key).add(new KeyValue<>(key, value));\n        this.size++;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, String> permits = new SimpleMap<>();\n        System.out.println(permits.put(\"KX-482\", \"Ines\"));\n        System.out.println(permits.put(\"BT-907\", \"Theo\"));\n        System.out.println(permits.put(\"KX-482\", \"Rafael\"));\n        System.out.println(permits.get(\"KX-482\") + \", \" + permits.size() + \" permits\");\n    }\n}\n","solution":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public V put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                V old = pair.getValue();\n                pair.setValue(value);\n                return old;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        return null;\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<String, String> permits = new SimpleMap<>();\n        System.out.println(permits.put(\"KX-482\", \"Ines\"));\n        System.out.println(permits.put(\"BT-907\", \"Theo\"));\n        System.out.println(permits.put(\"KX-482\", \"Rafael\"));\n        System.out.println(permits.get(\"KX-482\") + \", \" + permits.size() + \" permits\");\n    }\n}\n","hints":["The header becomes `public V put(K key, V value)`. Go through `bucketFor(key)` first, as the lesson's `put` does.","When a pair's key equals the key, keep `pair.getValue()` in a variable `V old`, call `pair.setValue(value)`, and `return old;`. After the loop, add the new pair, count it, and `return null;`."],"tests":[{"name":"Test 1","stdin":"","call":"SimpleMap<String, String> permits = new SimpleMap<>();\nSystem.out.println(permits.put(\"KX-482\", \"Ines\"));\nSystem.out.println(permits.put(\"BT-907\", \"Theo\"));\nSystem.out.println(permits.put(\"KX-482\", \"Rafael\"));\nSystem.out.println(permits.get(\"KX-482\") + \", \" + permits.size() + \" permits\");\n","expect":"null\nnull\nInes\nRafael, 2 permits","hidden":false},{"name":"Test 2","stdin":"","call":"SimpleMap<String, Integer> map = new SimpleMap<>();\nString[] keys = {\"Aa\", \"BB\", \"Aa\", \"BB\", \"Aa\", \"C\"};\nfor (int i = 0; i < keys.length; i++) {\n    System.out.print(map.put(keys[i], i) + \" \");\n}\nSystem.out.println();\nString start = \"B\";\nSystem.out.println(map.get(\"Aa\") + \" \" + map.get(start + \"B\") + \" \" + map.get(\"C\") + \" \" + map.size());\n","expect":"null null 0 1 2 null\n4 3 5 3","hidden":true},{"name":"Test 3","stdin":"","call":"SimpleMap<Integer, String> map = new SimpleMap<>();\nfor (int i = 0; i < 40; i++) {\n    map.put(i % 13 * 1000, \"v\" + i);\n}\nSystem.out.println(map.size() + \" \" + map.get(0) + \" \" + map.get(12000) + \" \" + map.get(5000));\nSystem.out.println(map.put(Integer.valueOf(3000), \"new\") + \" \" + map.size());\n","expect":"13 v39 v38 v31\nv29 13","hidden":true}],"require":[{"pattern":"\\bpublic\\s+V\\s+put\\s*\\(","message":"Make `put` return the old value: `public V put(K key, V value)`."}],"forbid":[],"more":[{"task":"An office mailroom's map from pigeonhole numbers to the people who use them is the SimpleMap of this step, with one change: its constructor takes the number of buckets to start with. An Integer's hash code is its own value. What does this program print?\n","kind":"predict","seed":"public class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> pigeonholes = new SimpleMap<>(4);\n        pigeonholes.put(11, \"Kenji\");\n        pigeonholes.put(12, \"Marisol\");\n        pigeonholes.put(13, \"Olu\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.bucketCount());\n        pigeonholes.put(14, \"Farida\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.bucketCount());\n        pigeonholes.put(12, \"Rasmus\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.get(12));\n        System.out.println(pigeonholes.remove(13) + \" \" + pigeonholes.remove(15) + \" \" + pigeonholes.size());\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap(int bucketCount) {\n        this.buckets = new ArrayList[bucketCount];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                pair.setValue(value);\n                return;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        if (this.size > 0.75 * this.buckets.length) {\n            grow();\n        }\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public V remove(K key) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (int i = 0; i < bucket.size(); i++) {\n            if (bucket.get(i).getKey().equals(key)) {\n                this.size--;\n                return bucket.remove(i).getValue();\n            }\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void grow() {\n        ArrayList<KeyValue<K, V>>[] old = this.buckets;\n        this.buckets = new ArrayList[old.length * 2];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        for (ArrayList<KeyValue<K, V>> bucket : old) {\n            for (KeyValue<K, V> pair : bucket) {\n                bucketFor(pair.getKey()).add(pair);\n            }\n        }\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public int bucketCount() {\n        return this.buckets.length;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> pigeonholes = new SimpleMap<>(4);\n        pigeonholes.put(11, \"Kenji\");\n        pigeonholes.put(12, \"Marisol\");\n        pigeonholes.put(13, \"Olu\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.bucketCount());\n        pigeonholes.put(14, \"Farida\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.bucketCount());\n        pigeonholes.put(12, \"Rasmus\");\n        System.out.println(pigeonholes.size() + \" \" + pigeonholes.get(12));\n        System.out.println(pigeonholes.remove(13) + \" \" + pigeonholes.remove(15) + \" \" + pigeonholes.size());\n    }\n}\n// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap(int bucketCount) {\n        this.buckets = new ArrayList[bucketCount];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                pair.setValue(value);\n                return;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        if (this.size > 0.75 * this.buckets.length) {\n            grow();\n        }\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public V remove(K key) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (int i = 0; i < bucket.size(); i++) {\n            if (bucket.get(i).getKey().equals(key)) {\n                this.size--;\n                return bucket.remove(i).getValue();\n            }\n        }\n        return null;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void grow() {\n        ArrayList<KeyValue<K, V>>[] old = this.buckets;\n        this.buckets = new ArrayList[old.length * 2];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        for (ArrayList<KeyValue<K, V>> bucket : old) {\n            for (KeyValue<K, V> pair : bucket) {\n                bucketFor(pair.getKey()).add(pair);\n            }\n        }\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public int bucketCount() {\n        return this.buckets.length;\n    }\n}\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n","hints":["With 4 buckets, the map grows when the size goes above 0.75 * 4 = 3. Three people don't make it grow; the fourth does, and then there are 8 buckets.","Putting pigeonhole 12 again changes the person in it but not the size. `remove` returns the removed value, or `null` for a pigeonhole that isn't in the map."],"tests":[{"name":"Output","stdin":"","expect":"3 4\n4 8\n4 Rasmus\nOlu null 3","hidden":false}],"require":[],"forbid":[],"lines":["3 4","4 8","4 Rasmus","Olu null 3"]},{"task":"`SimpleMap.java` has everything from this step except the body of `grow`, so the map never gets more than its 8 buckets. `put` already calls `grow` when the size goes above 0.75 times the number of buckets. Write `grow`: it makes the array of buckets twice as long, with an empty list in each place, and puts every pair into its bucket in the new array. The check runs:\n\n```java\nSimpleMap<Integer, String> map = new SimpleMap<>();\nfor (int i = 1; i <= 7; i++) {\n    map.put(i * 5, \"value \" + i);\n}\nSystem.out.println(map.size() + \" keys in \" + map.bucketCount() + \" buckets\");\nSystem.out.println(map.get(5) + \", \" + map.get(10) + \", \" + map.get(35) + \", \" + map.get(40));\n```\n\nand expects:\n\n```\n7 keys in 16 buckets\nvalue 1, value 2, value 7, null\n```\n","kind":"code","seed":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                pair.setValue(value);\n                return;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        if (this.size > 0.75 * this.buckets.length) {\n            grow();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void grow() {\n\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public int bucketCount() {\n        return this.buckets.length;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> map = new SimpleMap<>();\n        for (int i = 1; i <= 7; i++) {\n            map.put(i * 5, \"value \" + i);\n        }\n        System.out.println(map.size() + \" keys in \" + map.bucketCount() + \" buckets\");\n        System.out.println(map.get(5) + \", \" + map.get(10) + \", \" + map.get(35) + \", \" + map.get(40));\n    }\n}\n","solution":"// ==== SimpleMap.java ====\nimport java.util.ArrayList;\n\npublic class SimpleMap<K, V> {\n    private ArrayList<KeyValue<K, V>>[] buckets;\n    private int size;\n\n    @SuppressWarnings(\"unchecked\")\n    public SimpleMap() {\n        this.buckets = new ArrayList[8];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        this.size = 0;\n    }\n\n    private ArrayList<KeyValue<K, V>> bucketFor(K key) {\n        int index = Math.abs(key.hashCode() % this.buckets.length);\n        return this.buckets[index];\n    }\n\n    public void put(K key, V value) {\n        ArrayList<KeyValue<K, V>> bucket = bucketFor(key);\n        for (KeyValue<K, V> pair : bucket) {\n            if (pair.getKey().equals(key)) {\n                pair.setValue(value);\n                return;\n            }\n        }\n        bucket.add(new KeyValue<>(key, value));\n        this.size++;\n        if (this.size > 0.75 * this.buckets.length) {\n            grow();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private void grow() {\n        ArrayList<KeyValue<K, V>>[] old = this.buckets;\n        this.buckets = new ArrayList[old.length * 2];\n        for (int i = 0; i < this.buckets.length; i++) {\n            this.buckets[i] = new ArrayList<>();\n        }\n        for (ArrayList<KeyValue<K, V>> bucket : old) {\n            for (KeyValue<K, V> pair : bucket) {\n                bucketFor(pair.getKey()).add(pair);\n            }\n        }\n    }\n\n    public V get(K key) {\n        for (KeyValue<K, V> pair : bucketFor(key)) {\n            if (pair.getKey().equals(key)) {\n                return pair.getValue();\n            }\n        }\n        return null;\n    }\n\n    public int size() {\n        return this.size;\n    }\n\n    public int bucketCount() {\n        return this.buckets.length;\n    }\n}\n\n// ==== KeyValue.java ====\npublic class KeyValue<K, V> {\n    private K key;\n    private V value;\n\n    public KeyValue(K key, V value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public K getKey() {\n        return this.key;\n    }\n\n    public V getValue() {\n        return this.value;\n    }\n\n    public void setValue(V value) {\n        this.value = value;\n    }\n}\n\n// ==== Main.java ====\npublic class Main {\n    public static void main(String[] args) {\n        SimpleMap<Integer, String> map = new SimpleMap<>();\n        for (int i = 1; i <= 7; i++) {\n            map.put(i * 5, \"value \" + i);\n        }\n        System.out.println(map.size() + \" keys in \" + map.bucketCount() + \" buckets\");\n        System.out.println(map.get(5) + \", \" + map.get(10) + \", \" + map.get(35) + \", \" + map.get(40));\n    }\n}\n","hints":["Keep the old array in a variable, `ArrayList<KeyValue<K, V>>[] old = this.buckets;`, then set `this.buckets = new ArrayList[old.length * 2];` and fill it with empty lists, as the constructor does.","Then go through every bucket of `old`, and every pair in it, and add the pair to `bucketFor(pair.getKey())`. That picks its bucket in the new array, since `bucketFor` divides by `this.buckets.length`. Copying old bucket 2 to new bucket 2 would lose keys: 10 % 8 is 2, but 10 % 16 is 10."],"tests":[{"name":"Test 1","stdin":"","call":"SimpleMap<Integer, String> map = new SimpleMap<>();\nfor (int i = 1; i <= 7; i++) {\n    map.put(i * 5, \"value \" + i);\n}\nSystem.out.println(map.size() + \" keys in \" + map.bucketCount() + \" buckets\");\nSystem.out.println(map.get(5) + \", \" + map.get(10) + \", \" + map.get(35) + \", \" + map.get(40));\n","expect":"7 keys in 16 buckets\nvalue 1, value 2, value 7, null","hidden":false},{"name":"Test 2","stdin":"","call":"SimpleMap<String, Integer> map = new SimpleMap<>();\nfor (int i = 0; i < 100; i++) {\n    map.put(\"key\" + i, i);\n}\nint found = 0;\nfor (int i = 0; i < 100; i++) {\n    if (map.get(\"key\" + i) == i) {\n        found++;\n    }\n}\nSystem.out.println(map.size() + \" \" + map.bucketCount() + \" \" + found);\nmap.put(\"key50\", -1);\nSystem.out.println(map.size() + \" \" + map.get(\"key50\") + \" \" + map.get(\"key100\"));\n","expect":"100 256 100\n100 -1 null","hidden":true},{"name":"Test 3","stdin":"","call":"SimpleMap<Integer, Integer> map = new SimpleMap<>();\nfor (int i = -30; i < 30; i++) {\n    map.put(i * 37, i);\n}\nint found = 0;\nfor (int i = -30; i < 30; i++) {\n    if (map.get(i * 37) == i) {\n        found++;\n    }\n}\nSystem.out.println(map.size() + \" \" + map.bucketCount() + \" \" + found);\n","expect":"60 128 60","hidden":true}],"require":[],"forbid":[]}]}