This repository has been archived by the owner on Aug 31, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 163
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Python] Add tuples concept exercise (#1824)
* New tuples concept exercise design file. * New tuples concept exercise example implementation file. * New tuples concept exercise config file. * New tuples concept exercist after file w TODO. * New tuples concept exercist hints file. * New tuples concept exercise introduction file. * New tuples concept exercise instructions file. * New tuples concept exercise boilerplate file. * New tuples concept exercise cleaned boilerplate file. * New tuples concept exercise tests. * Ran prettier to clean up file markdown formatting. Edited language and cleaned up bloat. * Ran prettier to correct markdown formatting and dleted star operator as learning objective. * Removed tuple multiplication with star operator. * Edited to remove multiply function. * Edited to remove multiply function test case. * Fixed quoting on Scrimshaw Whale's tooth to match quoting style. * Ran prettier for config.json * Edits and adjustments per PR feedback and style guides. Also corrected introduction.md file name spelling. * Edited for clarity and brevity per PR feedback. Removed excess concepts and code examples. * Re-worked final task to be a returned report string rather than print()-ing of content. Adjusted instructions accordingly. * Cleaned up per PR feedback. Removed excess lines. * Changed final test to support altered task for report string. Removed context handler decorator for re-routing stdout and extra imports. * Corrected terminal output code exxample for task 4. * Removed print as a prerequisite of the exercise. Added absolute link for tuples.md refrence doc. * Removed excess PyTest config from test class. * Added tuples concept exercise information and uuid. * Ran prettier on config file, since I forgot to.
- Loading branch information
Showing
10 changed files
with
582 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
165 changes: 165 additions & 0 deletions
165
languages/python/exercises/concept/tuples/.docs/after.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
In Python, a [tuple](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/tuple.md) is an immutable collection of items in _sequence_. Like most collections (_see the built-ins [`list`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/list.md), [`dict`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/dict.md) and [`set`](https://github.com/exercism/v3/blob/master/languages/python/reference/concepts/builtin_types/set.md)_), tuples can hold any (or multiple) data type(s) -- including other tuples. Like any [sequence](https://docs.python.org/3/library/stdtypes.html#sequence-types-list-tuple-range), items are referenced by 0-based index number, and can be copied in whole or in part via _slice notation_. Tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). | ||
|
||
Tuples take up very little memory space compared to other collection types and have constant (_O(1)_) access time. However, they cannot be resized, sorted, or altered once created, so are less flexible when frequent changes or updates to data are needed. | ||
|
||
## Tuple Construction | ||
|
||
Tuples can be formed in multiple ways, using either the `tuple` class constructor or the `tuple` literal declaration. | ||
|
||
### Using the `tuple()` constructor empty or with an _iterable_: | ||
|
||
```python | ||
>>> no_elements = tuple() | ||
() | ||
|
||
#the string elements (characters) are iterated through and added to the tuple | ||
>>> multiple_elements_string = tuple("Timbuktu") | ||
('T', 'i', 'm', 'b', 'u', 'k', 't', 'u') | ||
|
||
>>> multiple_elements_list = tuple(["Parrot", "Bird", 334782]) | ||
("Parrot", "Bird", 334782) | ||
|
||
>>> multiple_elements_set = tuple({2, 3, 5, 7, 11}) | ||
(2,3,5,7,11) | ||
|
||
|
||
""" | ||
The iteration default for dictionaries is over the keys. | ||
To include both keys and values in a tuple made from a dictionary, use dict.items(), | ||
which returns a list of (key, value) tuples. | ||
""" | ||
source_data = {"fish": "gold", "monkey": "brown"} | ||
>>> multiple_elements_dict_1 = tuple(source_data) | ||
('fish', 'monkey') | ||
|
||
>>> multiple_elements_dict_2 = tuple(source_data.items()) | ||
(('fish', 'gold'), ('monkey', 'brown')) | ||
|
||
|
||
""" | ||
because the tuple constructor only takes _iterables_ (or nothing), it is much easier to create | ||
a one-tuple via the literal method. | ||
""" | ||
>>> one_element = tuple([16]) | ||
(16,) | ||
|
||
``` | ||
|
||
#### Declaring a tuple as a _literal_ : | ||
|
||
```python | ||
>>> no_elements = () | ||
() | ||
|
||
>>> one_element = ("Guava",) | ||
("Guava",) | ||
|
||
>>> elements_separated_with_commas = "Parrot", "Bird", 334782 | ||
("Parrot", "Bird", 334782) | ||
|
||
>>> elements_with_commas_and_parentheses = ("Triangle", 60, 60, 60) | ||
("Triangle", 60, 60, 60) | ||
|
||
>>> nested_data_structures = ({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) | ||
({"fish": "gold", "monkey": "brown", "parrot" : "grey"}, ("fish", "mammal", "bird")) | ||
|
||
#using the plus + operator unpacks each tuple and creates a new tuple. | ||
>>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") | ||
("George", 5, "cat", "Tabby") | ||
|
||
#likewise, using the multiplication operator * is the equvilent of using + n times | ||
>>> first_group = ("cat", "dog", "elephant") | ||
|
||
>>> multiplied_group = first_group * 3 | ||
('cat', 'dog', 'elephant', 'cat', 'dog', 'elephant', 'cat', 'dog', 'elephant') | ||
|
||
``` | ||
|
||
Note that generally parentheses are not _required_ to create a `tuple` literal - only commas. Parentheses are required in cases of ambiguity, such as an empty or one-item tuple or where a function takes a tuple as an argument. | ||
|
||
## Tuples as related information | ||
|
||
Tuples are often used as _records_ containing heterogeneous data that is _organizationally_ or _conceptually_ related and treated as a single unit of information. | ||
|
||
```python | ||
|
||
>>> student_info = ("Alyssa", "grade 3", "female", 8 ) | ||
|
||
``` | ||
|
||
Tuples are also used when homogeneous immutable sequences of data are needed for [`hashability`](https://docs.python.org/3/glossary.html#hashable), storage in a set, or creation of keys in a dictionary. | ||
|
||
Note that while tuples are in most cases _immutable_, because they can contain _any_ data structure or object they can become mutable if any of their elements is a _mutable type_. Using a mutable data type within a tuple will make the enclosing tuple un-hashable. | ||
|
||
```python | ||
|
||
>>> cmyk_color_map = { | ||
(.69, .3, .48, .1) : ("Teal 700", (59, 178, 146), 0x3BB292), | ||
(0, .5, 1, 0) : ("Pantone 151", (247, 127, 1), 0xF77F01), | ||
(.37, .89, 0, .44) : ("Pantone 267", (89, 16, 142), 0x59108E), | ||
(0, 1, .46, .45) : ("Pantone 228", (140, 0, 76), 0x8C004C) | ||
} | ||
|
||
>>>> unique_rgb_colors = { | ||
(59, 178, 146), | ||
(247, 127, 1), | ||
(89, 16, 142), | ||
(140, 0, 76), | ||
(76, 0, 140) | ||
} | ||
|
||
>>> teal_700 = hash((59, 178, 146)) | ||
|
||
>>> teal_700 = hash(("Pantone 228", [(140, 0, 76), 0x8C004C])) | ||
Traceback (most recent call last): | ||
File "<stdin>", line 1, in <module> | ||
TypeError: unhashable type: 'list' | ||
|
||
``` | ||
|
||
## Accessing data inside a tuple | ||
|
||
Items inside tuples (_like the sequence types `string` and `list`_), can be accessed via 0-based index and _bracket notation_. Indexes can be from **`left`** --> **`right`** (_starting at zero_) or **`right`** --> **`left`** (_starting at -1_). | ||
|
||
Items inside tuples can also be _iterated over_ in a loop using `for item in` syntax. | ||
|
||
```python | ||
|
||
>>> student_info = ("Alyssa", "grade 3", "female", 8 ) | ||
|
||
#name is at index 0 or index -4 | ||
>>> student_name = student_info[0] | ||
Alyssa | ||
|
||
>>> student_name = student_info[-4] | ||
Alyssa | ||
|
||
#grade is at index 1 or index -3 | ||
>>> student_grade = student_info[1] | ||
'grade 3' | ||
|
||
>>> student_grade = student_info[-3] | ||
'grade 3' | ||
|
||
#age is at index 3 or index -1 | ||
>>> student_age_1 = student_info[3] | ||
8 | ||
|
||
>>> student_age_2 = student_info[-1] | ||
8 | ||
|
||
|
||
>>> for item in student_info: | ||
>>> print(item) | ||
|
||
.... | ||
Alyssa | ||
grade 3 | ||
female | ||
8 | ||
|
||
``` | ||
|
||
## Extended tuples and related data types | ||
|
||
Tuples are often used as _records_, but the data inside them can only be accessed via _position_/_index_. The [`namedtuple()`](https://docs.python.org/3/library/collections.html#collections.namedtuple) class in the [`collections`](https://docs.python.org/3/library/collections.html#module-collections) module extends basic tuple functionality to allow access of elements by _name_. Additionally, users can adapt a [`dataclass`](https://docs.python.org/3/library/dataclasses.html) to provide similar named attribute functionality, with a some [pros and cons](https://stackoverflow.com/questions/51671699/data-classes-vs-typing-namedtuple-primary-use-cases). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
## General | ||
|
||
- [Tuples](https://docs.python.org/3/tutorial/datastructures.html#tuples-and-sequences) are immutable. | ||
[Sequence Types](https://docs.python.org/3/library/stdtypes.html#typesseq) that can contain any data type. | ||
- Tuples are [iterable](https://docs.python.org/3/glossary.html#term-iterable). | ||
- Elements within tuples can be accessed via [bracket notation](https://stackoverflow.com/questions/30250282/whats-the-difference-between-the-square-bracket-and-dot-notations-in-python), using a zero-based index. | ||
- Other [Common Sequence Operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations) can also be used when working with tuples. | ||
|
||
## 1. Extract coordinates | ||
|
||
- Remember: tuples allow access via _index_, using _brackets_. Indexes start from the left at zero. | ||
|
||
## 2. Format coordinates | ||
|
||
- Check [`class tuple`](https://docs.python.org/3/library/stdtypes.html#tuple) for more details on tuples. | ||
- Check [`class str`](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str) for more details on strings. | ||
|
||
## 3. Match coordinates | ||
|
||
- What methods could be used here for for [testing membership](https://docs.python.org/3/reference/expressions.html#membership-test-operations)?. | ||
- Check [`class tuple`](https://docs.python.org/3/library/stdtypes.html#tuple) for more details on tuples. | ||
- Could you re-use your `convert_coordinate()` function? | ||
|
||
## 4. Combine matched records | ||
|
||
- Remember that tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). | ||
- Could you re-use your `compare_records()` function here? | ||
|
||
## 5. "Clean up" & format a report of all records | ||
|
||
- Remember: tuples are _immutable_, but the contents can be accessed via _index_ using _bracket notation_. | ||
- Tuples don't have to use parentheses unless there is _ambiguity_. | ||
- Python has multiple methods of string formatting. [`str.format()`](https://docs.python.org/3/library/stdtypes.html#str.format) and [`f-strings`](https://docs.python.org/3/tutorial/inputoutput.html#formatted-string-literals) are two very common ones. | ||
- There are multiple textual formatting options available via Pythons [`format specification mini-language`](https://docs.python.org/3/library/string.html#format-specification-mini-language). |
107 changes: 107 additions & 0 deletions
107
languages/python/exercises/concept/tuples/.docs/instructions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
Aazra and Rui are teammates competing in a pirate-themed treasure hunt. One has a list of treasures with map coordinates, the other a list of location names with map coordinates. They've also been given blank maps with a starting place marked YOU ARE HERE. | ||
|
||
<br> | ||
<table> | ||
<tr><th>Azara's List</th><th></th><th>Rui's List</th></tr> | ||
<tr><td> | ||
|
||
| Treasure | Coordinates | | ||
| --------------------------- | ----------- | | ||
| Amethyst Octopus | 1F | | ||
| Angry Monkey Figurine | 5B | | ||
| Antique Glass Fishnet Float | 3D | | ||
| Brass Spyglass | 4B | | ||
| Carved Wooden Elephant | 8C | | ||
| Crystal Crab | 6A | | ||
| Glass Starfish | 6D | | ||
| Model Ship in Large Bottle | 8A | | ||
| Pirate Flag | 7F | | ||
| Robot Parrot | 1C | | ||
| Scrimshaw Whale's Tooth | 2A | | ||
| Silver Seahorse | 4E | | ||
| Vintage Pirate Hat | 7E | | ||
|
||
</td><td></td><td> | ||
|
||
| Location Name | Coordinates | Quandrant | | ||
| ------------------------------------- | ----------- | --------- | | ||
| Seaside Cottages | ("1", "C") | Blue | | ||
| Aqua Lagoon (Island of Mystery) | ("1", "F") | Yellow | | ||
| Deserted Docks | ("2", "A") | Blue | | ||
| Spiky Rocks | ("3", "D") | Yellow | | ||
| Abandoned Lighthouse | ("4", "B") | Blue | | ||
| Hidden Spring (Island of Mystery) | ("4", "E") | Yellow | | ||
| Stormy Breakwater | ("5", "B") | Purple | | ||
| Old Schooner | ("6", "A") | Purple | | ||
| Tangled Seaweed Patch | ("6", "D") | Orange | | ||
| Quiet Inlet (Island of Mystery) | ("7", "E") | Orange | | ||
| Windswept Hilltop (Island of Mystery) | ("7", "F") | Orange | | ||
| Harbor Managers Office | ("8", "A") | Purple | | ||
| Foggy Seacave | ("8", "C") | Purple | | ||
|
||
</td></tr> | ||
</table> | ||
|
||
<br> | ||
|
||
But things are a bit disorganized: Azara's coordinates appear to be formatted and sorted differently from Rui's, and they have to keep looking from one list to the other to figure out which treasures go with which locations. Being budding pythonistas, they've come to you for help in writing a small program (a set of functions, really) to better organize their hunt information. | ||
|
||
## 1. Extract coordinates | ||
|
||
Implement the `get_cooordinate()` function that takes a `(treasure, coordinate)` pair from Azaras list and returns only the extracted map coordinate. | ||
| ||
|
||
```python | ||
>>> get_coordinate(("Scrimshaw Whale's Tooth", "2A")) | ||
"2A" | ||
``` | ||
|
||
## 2. Format coordinates | ||
|
||
Implement the `convert_coordinate()` function that takes a coordinate in the format "2A" and returns a tuple in the format `("2", "A")`. | ||
|
||
| ||
|
||
```python | ||
>>> convert_coordinate("2A") | ||
("2", "A") | ||
``` | ||
|
||
## 3. Match coordinates | ||
|
||
Implement the `compare_records()` function that takes a `(treasure, coordinate)` pair and a `(location, coordinate, quadrant)` record and compares coordinates from each. Return **`True`** if the coordinates "match", and return **`False`** if they do not. Re-format coordinates as needed for accurate comparison. | ||
|
||
```python | ||
>>> compare_records(('Brass Spyglass', '4B'),('Seaside Cottages', ("1", "C"), 'blue')) | ||
False | ||
|
||
>>> compare_records(('Model Ship in Large Bottle', '8A'), ('Harbor Managers Office', ("8", "A"), 'purple')) | ||
True | ||
``` | ||
|
||
## 4. Combine matched records | ||
|
||
Implement the `create_record()` function that takes a `(treasure, coordinate)` pair from Azaras list and a `(location, coordinate, quadrant)` record from Ruis list and returns `(treasure, coordinate, location, coordinate, quadrant)` **if the coordinates match**. If the coordinats _do not_ match, return the string "not a match.". Re-format the coordinate as needed for accurate comparison. | ||
|
||
```python | ||
>>> create_record(('Brass Spyglass', '4B'),('Abandoned Lighthouse', ("4", "B"), 'Blue')) | ||
('Brass Spyglass', '4B', 'Abandoned Lighthouse', ("4", "B"), 'Blue') | ||
|
||
>>> create_record(('Brass Spyglass', '4B'),(("1", "C"), 'Seaside Cottages', 'blue')) | ||
"not a match." | ||
``` | ||
|
||
## 5. "Clean up" & make a report of all records | ||
|
||
Clean up the combined records from Azara and Rui so that there's only one set of coordinates per record. Make a report so they can see one list of everything they need to put on their maps. | ||
Implement the `clean_up()` function that takes a tuple of tuples (_everything from both lists_), looping through the _outer_ tuple, dropping the unwanted coordinates from each _inner_ tuple and adding each to a 'report'. Format and return the 'report' so that there is one cleaned record on each line. | ||
|
||
```python | ||
>>> clean_up((('Brass Spyglass', '4B', 'Abandoned Lighthouse', '("4", "B")', 'Blue'), ('Vintage Pirate Hat', '7E', 'Quiet Inlet (Island of Mystery)', '("7", "E")', 'Orange'), ('Crystal Crab', '6A', 'Old Schooner', '("6", "A")', 'Purple'))) | ||
|
||
""" | ||
('Brass Spyglass', 'Abandoned Lighthouse', '("4", "B")', 'Blue')\n | ||
('Vintage Pirate Hat', 'Quiet Inlet (Island of Mystery)', '("7", "E")', 'Orange')\n | ||
('Crystal Crab', 'Old Schooner', '("6", "A")','Purple')\n | ||
""" | ||
``` |
55 changes: 55 additions & 0 deletions
55
languages/python/exercises/concept/tuples/.docs/introduction.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
In Python, a [tuple](https://docs.python.org/3/library/stdtypes.html#tuple) is an immutable collection of items in _sequence_. Like most collections, tuples can hold any (or multiple) data type(s) -- including other tuples. Like any sequence, items are referenced by 0-based index number. Tuples support all [common sequence operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations). | ||
|
||
## Tuple Construction | ||
|
||
Tuples can be formed in multiple ways, using either the `tuple` class constructor or the `tuple` literal declaration. | ||
|
||
#### Using the `tuple()` constructor: | ||
|
||
```python | ||
#elements are iterated through and added to the tuple in order | ||
>>> multiple_elements_string = tuple("Timbuktu") | ||
('T', 'i', 'm', 'b', 'u', 'k', 't', 'u') | ||
|
||
>>> multiple_elements = tuple(("Parrot", "Bird", 334782)) | ||
("Parrot", "Bird", 334782) | ||
``` | ||
|
||
#### Declaring a tuple _literal_ : | ||
|
||
```python | ||
>>> elements_separated_with_commas = "Parrot", "Bird", 334782 | ||
("Parrot", "Bird", 334782) | ||
|
||
>>> elements_with_commas_and_parentheses = ("Triangle", (60, 60, 60)) | ||
("Triangle", (60, 60, 60)) | ||
``` | ||
|
||
## Concatenation | ||
|
||
Tuples can be _concatenated_ via the plus `+` operator, which returns a new tuple. | ||
|
||
```python | ||
>>> new_via_concatenate = ("George", 5) + ("cat", "Tabby") | ||
("George", 5, "cat", "Tabby") | ||
``` | ||
|
||
## Accessing data | ||
|
||
Items inside tuples can be accessed via 0-based index and _bracket notation_. | ||
|
||
```python | ||
student_info = ("Alyssa", "grade 3", "female", 8 ) | ||
|
||
#gender is at index 2 | ||
>>> student_gender = student_info[2] | ||
female | ||
``` | ||
|
||
## Iterating through a tuple | ||
|
||
Items inside tuples can be _iterated over_ in a loop using `for item in` syntax. | ||
|
||
## Checking membership | ||
|
||
The `in` operator can be used to check membership in a tuple. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"authors": [ | ||
{ | ||
"github_username": "bethanyg", | ||
"exercism_username": "BethanyG" | ||
} | ||
] | ||
} |
Oops, something went wrong.