{"id":"tuples-purpose","slug":"why-tuples","title":"What tuples are for","text":"A list can do almost everything a tuple can, and more. So why have tuples at all? Because a tuple says something about the data.\n\nA list is a collection that may grow and shrink, usually of things of the same kind: the guests, the scores, the words. A tuple is a fixed group of values that belong together and only make sense together: the x and y of a point, the red, green and blue of a color, the year, month and day of a date. A point always has exactly two coordinates. Nobody should append a third one to it, and with a tuple, nobody can.\n\nA function that works with such values gives back a new tuple instead of changing the old one:\n\n```python\ndef move(point: tuple, dx: int, dy: int) -> tuple:\n    return (point[0] + dx, point[1] + dy)\n\n\nstart = (2, 5)\nend = move(start, 3, -1)\nprint(start, end)\n```\n\n```output\n(2, 5) (5, 4)\n```\n\n`move` can't change `start` by accident, so there are no side effects to worry about: the original point is safe.\n\n### Tuples as dictionary keys\n\nBecause a tuple can't change, it can be a dictionary key, which a list can't. This makes a dictionary a handy map of a grid. The key is a pair of a row and a column, and only the squares that have something on them need to be stored:\n\n```python\ntreasures = {}\ntreasures[(2, 3)] = \"gold\"\ntreasures[(0, 1)] = \"map\"\n\nprint(treasures)\nprint(treasures[(2, 3)])\nprint((1, 1) in treasures)\n```\n\n```output\n{(2, 3): 'gold', (0, 1): 'map'}\ngold\nFalse\n```\n\nWith a list as the key, as in `treasures[[2, 3]] = \"gold\"`, Python would stop with the `TypeError` about an unhashable type from the dictionaries module.\n\nHere the dictionary also counts how often each square of a grid was visited, with the counting pattern from the dictionaries module:\n\n```python\nsteps = [(0, 0), (0, 1), (0, 0), (1, 1), (0, 0)]\nvisits = {}\nfor square in steps:\n    if square not in visits:\n        visits[square] = 0\n    visits[square] += 1\nprint(visits)\n```\n\n```output\n{(0, 0): 3, (0, 1): 1, (1, 1): 1}\n```\n","task":"The treasures of a map are in a dictionary whose keys are `(row, column)` tuples. Complete the program: it asks for a row and a column, as whole numbers, and prints what's in that square, or `Nothing here` if the square isn't a key. Use the prompts `Row: ` and `Column: `. An example run:\n\n```\nRow: 2\nColumn: 3\ngold\n```\n","kind":"code","seed":"treasures = {(2, 3): \"gold\", (0, 1): \"map\", (4, 4): \"ruby\"}\n","solution":"treasures = {(2, 3): \"gold\", (0, 1): \"map\", (4, 4): \"ruby\"}\n\nrow = int(input(\"Row: \"))\ncolumn = int(input(\"Column: \"))\nsquare = (row, column)\nif square in treasures:\n    print(treasures[square])\nelse:\n    print(\"Nothing here\")\n","hints":["Read both numbers with `int(input(...))`, then put them in a tuple: `square = (row, column)`.","Check whether the tuple is a key with `in`, and if it is, print `treasures[square]`.","The numbers have to be integers: the key `(2, 3)` isn't the same as `(\"2\", \"3\")`."],"tests":[{"name":"Test 1","stdin":"2\n3\n","expect":"Row: 2\nColumn: 3\ngold","hidden":false},{"name":"Test 2","stdin":"3\n2\n","expect":"Row: 3\nColumn: 2\nNothing here","hidden":false},{"name":"Test 3","stdin":"4\n4\n","expect":"Row: 4\nColumn: 4\nruby","hidden":true},{"name":"Test 4","stdin":"0\n1\n","expect":"Row: 0\nColumn: 1\nmap","hidden":true}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"def flip(point: tuple) -> tuple:\n    return (point[1], point[0])\n\n\ncorner = (1, 8)\nother = flip(corner)\nprint(other)\nprint(corner)\nboard = {corner: \"X\", other: \"O\"}\nprint(board[(8, 1)])\n","solution":"def flip(point: tuple) -> tuple:\n    return (point[1], point[0])\n\n\ncorner = (1, 8)\nother = flip(corner)\nprint(other)\nprint(corner)\nboard = {corner: \"X\", other: \"O\"}\nprint(board[(8, 1)])\n","hints":["`flip` makes a new tuple with the two values the other way around. `corner` itself can't change.","The dictionary has two tuple keys, `(1, 8)` and `(8, 1)`. Which value is stored under `(8, 1)`?"],"tests":[{"name":"Output","stdin":"","expect":"(8, 1)\n(1, 8)\nO","hidden":false}],"require":[],"forbid":[],"lines":["(8, 1)","(1, 8)","O"]},{"task":"Write a function `count_visits(squares)` that takes a list of `(row, column)` tuples and returns a dictionary in which each different square is a key and the value is how many times it's in the list.\n\nFor example, `count_visits([(0, 0), (1, 2), (0, 0)])` returns `{(0, 0): 2, (1, 2): 1}`.\n","kind":"code","seed":"def count_visits(squares: list) -> dict:\n    pass\n\n\nif __name__ == \"__main__\":\n    print(count_visits([(0, 0), (1, 2), (0, 0)]))\n","solution":"def count_visits(squares: list) -> dict:\n    visits = {}\n    for square in squares:\n        if square not in visits:\n            visits[square] = 0\n        visits[square] += 1\n    return visits\n\n\nif __name__ == \"__main__\":\n    print(count_visits([(0, 0), (1, 2), (0, 0)]))\n","hints":["A tuple can be a key, so each square tuple can be used as it is.","Use the counting pattern: if the square isn't a key yet, give it the value 0, then add one."],"tests":[{"name":"count_visits([(0, 0), (1, 2), (0, 0)])","stdin":"","call":"count_visits([(0, 0), (1, 2), (0, 0)])\n","expect":"{(0, 0): 2, (1, 2): 1}","hidden":false,"returns":true},{"name":"count_visits([(5, 5)])","stdin":"","call":"count_visits([(5, 5)])\n","expect":"{(5, 5): 1}","hidden":true,"returns":true},{"name":"count_visits([(1, 2), (2, 1), (1, 2), (2, 1), (1, 2)])","stdin":"","call":"count_visits([(1, 2), (2, 1), (1, 2), (2, 1), (1, 2)])\n","expect":"{(1, 2): 3, (2, 1): 2}","hidden":true,"returns":true}],"require":[],"forbid":[]}]}