{"id":"randomness-lists","slug":"picking-and-shuffling","title":"Picking, shuffling and drawing","text":"Random numbers often choose among things: an exercise from a list, the order of a quiz's questions, who goes first.\n\n### A random element\n\n`nextInt(size)` gives a number from 0 to size - 1: exactly the indexes of a list of that size. So `list.get(random.nextInt(list.size()))` is a random element, each one as likely as the others. A workout app picks the exercise of the day this way:\n\n```java\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> exercises = new ArrayList<>();\n        exercises.add(\"squats\");\n        exercises.add(\"push-ups\");\n        exercises.add(\"plank\");\n        exercises.add(\"lunges\");\n        Random random = new Random(8);\n        for (int day = 1; day <= 4; day++) {\n            String exercise = exercises.get(random.nextInt(exercises.size()));\n            System.out.println(\"Day \" + day + \": \" + exercise);\n        }\n    }\n}\n```\n\n```output\nDay 1: plank\nDay 2: lunges\nDay 3: plank\nDay 4: squats\n```\n\n- With `exercises.size()` as the bound, the code stays right when the list changes: add a fifth exercise, and it can come up too.\n- The same exercise can come up on several days. Each pick is a new draw that knows nothing about the earlier ones. Drawing without repeats comes later in this step.\n- An array works the same way: `array[random.nextInt(array.length)]`.\n\nAn empty list has no element to pick, and `nextInt(0)` has no number to give: the bound must be positive, or `nextInt` throws an exception.\n\n```java\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> exercises = new ArrayList<>();\n        Random random = new Random();\n        String exercise = exercises.get(random.nextInt(exercises.size()));\n        System.out.println(\"Today: \" + exercise);\n    }\n}\n```\n\n```crash\nException in thread \"main\" java.lang.IllegalArgumentException: bound must be positive\n\tat Main.main(Main.java:8)\n```\n\nWhen a list might be empty, check `isEmpty()` before you pick.\n\n### Shuffling\n\n`Collections.shuffle(list)` puts a list's elements in a random order, like shuffling a deck of cards. Give it a Random too, `Collections.shuffle(list, random)`, and it uses that one, so a seed gives the same order every time. A quiz app asks its questions in a new order every round:\n\n```java\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> questions = new ArrayList<>();\n        questions.add(\"How many sides does a hexagon have?\");\n        questions.add(\"Which metal is liquid at room temperature?\");\n        questions.add(\"What is the capital of Canada?\");\n        questions.add(\"Which gas do plants take in?\");\n        Collections.shuffle(questions, new Random(3));\n        for (int i = 0; i < questions.size(); i++) {\n            System.out.println((i + 1) + \". \" + questions.get(i));\n        }\n    }\n}\n```\n\n```output\n1. Which metal is liquid at room temperature?\n2. How many sides does a hexagon have?\n3. Which gas do plants take in?\n4. What is the capital of Canada?\n```\n\n- `shuffle` changes the list itself and returns nothing. Every element is still there, once; only the order is new.\n- Every possible order has about the same chance of coming up.\n- To keep the original order as well, shuffle a copy: `new ArrayList<>(questions)` makes one (module 14).\n- `Collections` is in `java.util`, like Random. Module 28 used its `sort`.\n\n### Drawing without repeats\n\nPicking with `nextInt` can pick the same element twice. When each element may come up only once, like names drawn out of a hat, there are two easy ways.\n\n**Shuffle, and take from the front.** To pick three different exercises for today, shuffle a copy of the list and take its first three elements.\n\n**Remove what you draw.** Pick a random index, and remove the element there. `list.remove(index)` returns the element it removed, so one line does both. What's drawn is no longer in the list, so it can't come up again, and the next bound, `list.size()`, is one smaller. A class decides the order of its presentations by drawing names:\n\n```java\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> hat = new ArrayList<>();\n        hat.add(\"Ines\");\n        hat.add(\"Tomasz\");\n        hat.add(\"Priya\");\n        hat.add(\"Kofi\");\n        Random random = new Random(21);\n        int turn = 1;\n        while (!hat.isEmpty()) {\n            String name = hat.remove(random.nextInt(hat.size()));\n            System.out.println(turn + \". \" + name);\n            turn++;\n        }\n    }\n}\n```\n\n```output\n1. Priya\n2. Ines\n3. Tomasz\n4. Kofi\n```\n\nA third way is to keep drawing, and throw away whatever was drawn before, checking with `contains`. It works too, but when most of the elements have been drawn, most of the draws are thrown away.\n","task":"A trivia night picks a random category for each round. Fill in the blanks so that `pickCategory` returns a random category from the list, each as likely as the others. `main` picks for three rounds with a seeded Random:\n\n```\nRound 1: science\nRound 2: sports\nRound 3: history\n```\n","kind":"fill","seed":"import java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> categories = new ArrayList<>();\n        categories.add(\"history\");\n        categories.add(\"science\");\n        categories.add(\"music\");\n        categories.add(\"sports\");\n        categories.add(\"movies\");\n        Random random = new Random(30);\n        for (int round = 1; round <= 3; round++) {\n            System.out.println(\"Round \" + round + \": \" + pickCategory(categories, random));\n        }\n    }\n\n    public static String pickCategory(ArrayList<String> categories, Random random) {\n        return categories.get(random.[[nextInt]](categories.[[size()]]));\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> categories = new ArrayList<>();\n        categories.add(\"history\");\n        categories.add(\"science\");\n        categories.add(\"music\");\n        categories.add(\"sports\");\n        categories.add(\"movies\");\n        Random random = new Random(30);\n        for (int round = 1; round <= 3; round++) {\n            System.out.println(\"Round \" + round + \": \" + pickCategory(categories, random));\n        }\n    }\n\n    public static String pickCategory(ArrayList<String> categories, Random random) {\n        return categories.get(random.nextInt(categories.size()));\n    }\n}\n","hints":["A random index of a list is a whole number from 0 to the list's size - 1: `nextInt` with the size as its bound.","The list's size is `categories.size()`, so the index is `random.nextInt(categories.size())`."],"tests":[{"name":"Five categories, seed 30","stdin":"","expect":"Round 1: science\nRound 2: sports\nRound 3: history","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<String> categories = new ArrayList<>();\ncategories.add(\"art\");\ncategories.add(\"food\");\nRandom random = new Random(4);\nfor (int i = 0; i < 6; i++) {\n    System.out.print(pickCategory(categories, random) + \" \");\n}\nSystem.out.println();\n","expect":"food food food food food art","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<String> categories = new ArrayList<>();\ncategories.add(\"geography\");\ncategories.add(\"animals\");\ncategories.add(\"books\");\nRandom random = new Random();\nHashSet<String> seen = new HashSet<>();\nfor (int i = 0; i < 300; i++) {\n    seen.add(pickCategory(categories, random));\n}\nSystem.out.println(\"all three came up: \" + (seen.size() == 3));\n","expect":"all three came up: true","hidden":true}],"require":[],"forbid":[],"more":[{"task":"A teacher gives every student the spelling words in a different order, and keeps the master list in its own order. Write the method `shuffledCopy(ArrayList<String> words, Random random)`, which returns a new list with the same words, shuffled with `Collections.shuffle` and the given Random. The list it's given must keep its order. The check runs:\n\n```java\nArrayList<String> words = new ArrayList<>();\nwords.add(\"rhythm\");\nwords.add(\"island\");\nwords.add(\"receive\");\nwords.add(\"necessary\");\nwords.add(\"calendar\");\nSystem.out.println(shuffledCopy(words, new Random(5)));\nSystem.out.println(words);\n```\n\nand expects:\n\n```\n[necessary, island, calendar, rhythm, receive]\n[rhythm, island, receive, necessary, calendar]\n```\n","kind":"code","seed":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> words = new ArrayList<>();\n        words.add(\"rhythm\");\n        words.add(\"island\");\n        words.add(\"receive\");\n        words.add(\"necessary\");\n        words.add(\"calendar\");\n        System.out.println(shuffledCopy(words, new Random(5)));\n        System.out.println(words);\n    }\n\n    public static ArrayList<String> shuffledCopy(ArrayList<String> words, Random random) {\n        return words;\n    }\n}\n","solution":"import java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> words = new ArrayList<>();\n        words.add(\"rhythm\");\n        words.add(\"island\");\n        words.add(\"receive\");\n        words.add(\"necessary\");\n        words.add(\"calendar\");\n        System.out.println(shuffledCopy(words, new Random(5)));\n        System.out.println(words);\n    }\n\n    public static ArrayList<String> shuffledCopy(ArrayList<String> words, Random random) {\n        ArrayList<String> copy = new ArrayList<>(words);\n        Collections.shuffle(copy, random);\n        return copy;\n    }\n}\n","hints":["Make a copy first: `ArrayList<String> copy = new ArrayList<>(words);`. Shuffling `words` itself would change the teacher's list.","Shuffle the copy with `Collections.shuffle(copy, random);` and return it."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<String> words = new ArrayList<>();\nwords.add(\"rhythm\");\nwords.add(\"island\");\nwords.add(\"receive\");\nwords.add(\"necessary\");\nwords.add(\"calendar\");\nSystem.out.println(shuffledCopy(words, new Random(5)));\nSystem.out.println(words);\n","expect":"[necessary, island, calendar, rhythm, receive]\n[rhythm, island, receive, necessary, calendar]","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<String> words = new ArrayList<>();\nwords.add(\"beautiful\");\nwords.add(\"Wednesday\");\nwords.add(\"separate\");\nRandom random = new Random(77);\nSystem.out.println(shuffledCopy(words, random));\nSystem.out.println(shuffledCopy(words, random));\nSystem.out.println(words);\n","expect":"[separate, Wednesday, beautiful]\n[separate, beautiful, Wednesday]\n[beautiful, Wednesday, separate]","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<String> words = new ArrayList<>();\nfor (int i = 1; i <= 8; i++) {\n    words.add(\"word\" + i);\n}\nArrayList<String> shuffled = shuffledCopy(words, new Random());\nSystem.out.println(\"a new list: \" + (shuffled != words));\nCollections.sort(shuffled);\nArrayList<String> sorted = new ArrayList<>(words);\nCollections.sort(sorted);\nSystem.out.println(\"the same words: \" + shuffled.equals(sorted));\n","expect":"a new list: true\nthe same words: true","hidden":true}],"require":[{"pattern":"Collections\\.shuffle\\s*\\(\\s*\\w+\\s*,\\s*random\\s*\\)","message":"Shuffle with `Collections.shuffle(..., random)`, using the Random from the parameter."}],"forbid":[]},{"task":"Housemates draw chores out of a hat. In `ChoreHat.java`, write the class `ChoreHat` with:\n\n- a constructor `ChoreHat(ArrayList<String> chores, Random random)`, which keeps a copy of the list, so that the list it was given isn't emptied by the draws\n- `draw()`, which picks an index with `random.nextInt` of how many chores are left, removes that chore from the hat and returns it. When the hat is empty, it returns `nothing left`.\n- `left()`, which returns how many chores are still in the hat\n\nThe check runs:\n\n```java\nArrayList<String> chores = new ArrayList<>();\nchores.add(\"dishes\");\nchores.add(\"vacuuming\");\nchores.add(\"trash\");\nChoreHat hat = new ChoreHat(chores, new Random(6));\nfor (int i = 0; i < 4; i++) {\n    System.out.println(hat.draw());\n}\nSystem.out.println(hat.left() + \" left, \" + chores.size() + \" chores in all\");\n```\n\nand expects:\n\n```\nvacuuming\ndishes\ntrash\nnothing left\n0 left, 3 chores in all\n```\n","kind":"code","seed":"// ==== ChoreHat.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class ChoreHat {\n\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> chores = new ArrayList<>();\n        chores.add(\"dishes\");\n        chores.add(\"vacuuming\");\n        chores.add(\"trash\");\n        ChoreHat hat = new ChoreHat(chores, new Random(6));\n        for (int i = 0; i < 4; i++) {\n            System.out.println(hat.draw());\n        }\n        System.out.println(hat.left() + \" left, \" + chores.size() + \" chores in all\");\n    }\n}\n","solution":"// ==== ChoreHat.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class ChoreHat {\n    private ArrayList<String> chores;\n    private Random random;\n\n    public ChoreHat(ArrayList<String> chores, Random random) {\n        this.chores = new ArrayList<>(chores);\n        this.random = random;\n    }\n\n    public String draw() {\n        if (this.chores.isEmpty()) {\n            return \"nothing left\";\n        }\n        return this.chores.remove(this.random.nextInt(this.chores.size()));\n    }\n\n    public int left() {\n        return this.chores.size();\n    }\n}\n\n// ==== Main.java ====\nimport java.util.ArrayList;\nimport java.util.Random;\n\npublic class Main {\n    public static void main(String[] args) {\n        ArrayList<String> chores = new ArrayList<>();\n        chores.add(\"dishes\");\n        chores.add(\"vacuuming\");\n        chores.add(\"trash\");\n        ChoreHat hat = new ChoreHat(chores, new Random(6));\n        for (int i = 0; i < 4; i++) {\n            System.out.println(hat.draw());\n        }\n        System.out.println(hat.left() + \" left, \" + chores.size() + \" chores in all\");\n    }\n}\n","hints":["In the constructor, keep a copy: `this.chores = new ArrayList<>(chores);`. Keep the Random in an instance variable too.","`draw()` returns `nothing left` when `this.chores.isEmpty()`. Otherwise it returns `this.chores.remove(this.random.nextInt(this.chores.size()))`: `remove` with an index returns the element it removed."],"tests":[{"name":"Test 1","stdin":"","call":"ArrayList<String> chores = new ArrayList<>();\nchores.add(\"dishes\");\nchores.add(\"vacuuming\");\nchores.add(\"trash\");\nChoreHat hat = new ChoreHat(chores, new Random(6));\nfor (int i = 0; i < 4; i++) {\n    System.out.println(hat.draw());\n}\nSystem.out.println(hat.left() + \" left, \" + chores.size() + \" chores in all\");\n","expect":"vacuuming\ndishes\ntrash\nnothing left\n0 left, 3 chores in all","hidden":false},{"name":"Test 2","stdin":"","call":"ArrayList<String> chores = new ArrayList<>();\nchores.add(\"laundry\");\nchores.add(\"plants\");\nchores.add(\"bathroom\");\nchores.add(\"shopping\");\nchores.add(\"cooking\");\nChoreHat hat = new ChoreHat(chores, new Random(31));\nSystem.out.println(hat.left());\nSystem.out.println(hat.draw() + \", \" + hat.draw());\nSystem.out.println(hat.left());\n","expect":"5\nbathroom, plants\n3","hidden":true},{"name":"Test 3","stdin":"","call":"ArrayList<String> chores = new ArrayList<>();\nfor (int i = 1; i <= 10; i++) {\n    chores.add(\"chore \" + i);\n}\nChoreHat hat = new ChoreHat(chores, new Random());\nHashSet<String> drawn = new HashSet<>();\nfor (int i = 0; i < 10; i++) {\n    drawn.add(hat.draw());\n}\nSystem.out.println(\"10 different chores: \" + (drawn.size() == 10 && chores.containsAll(drawn)));\nSystem.out.println(hat.draw() + \", \" + hat.left());\nChoreHat empty = new ChoreHat(new ArrayList<>(), new Random());\nSystem.out.println(empty.draw());\n","expect":"10 different chores: true\nnothing left, 0\nnothing left","hidden":true}],"require":[],"forbid":[]}]}