Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Concept & Exercise]: Sequences & Thalia's Tram Troubles #3220

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
4 changes: 2 additions & 2 deletions concepts/sequences/.meta/config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"blurb": "TODO: add blurb for this concept",
"authors": ["bethanyg", "cmccandless"],
"blurb": "A sequence is an ordered, indexable collection of items. All sequence types support a common set of operations, with lists supporting additional mutable operations. All sequences can be indexed into with bracket notation, copied in whole or in part using slice notation, and iterated over using the \"for item in <sequence>\".",
"authors": ["bethanyg", "meatball133"],
"contributors": []
}
174 changes: 173 additions & 1 deletion concepts/sequences/about.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,174 @@
#TODO: Add about for this concept.
# Sequences

A sequence is an ordered, indexable collection of items.
All sequence types support a common set of operations that include `in`/`not in`, `min()`/`max()`, `<sequence>.index`, `<sequence>.count()` and `<sequence>.len()`.
`lists` and `bytearray` support additional mutable operations such as [slice assignment][<url ref here>], `.append()`, `.extend()`, `.reverse()`, and `.copy()`.

All sequences can be indexed into using `<sequence>[<index number>]`, copied in whole or in part using `<sequence>[<start_index>:<stop_index>:<step>]`(\_a full copy can be made with `<sequence>[:]`), and iterated over using the `for item in <sequence>` construct.
`for index, item in enumerate(<sequence>)` can be used when both the element index and the element value are needed.

Pythons `list`, `tuple`, `str`, `bytes`, `bytearray` and `range` types all belong to this wider sequence type.
In the case of `str`, the “collection” is made up of unicode code points.
In the case of `bytes`, bytes.
Ranges are “collections” of numbers conforming to a `start:stop:step` rule.

## Common Sequence operations

### In operator

`in` checks if a sequence contains a value.
It returns `True` if the value is found, and `False` otherwise.

```python
>>> 1 in [1, 2, 3]
True

>>> 4 in [1, 2, 3]
False

>>> "a" in "abc"
True

>>> "d" in "abc"
False
```

It does not check if a value is in a sequence within a sequence.

```python
>>> "a" in ["abc", "def"]
False

>>> 1 in [[1, 2, 3], [4, 5, 6]]
False
```

### Not in operator

`Not in` checks if a sequence does not contain a value.
It does the reverse of `in`.

```python
>>> 1 not in [1, 2, 3]
False

>>> 4 not in [1, 2, 3]
True
```

### Get the length of a sequence

`len()` gives the length of a sequence.

```python
>>> len([1, 2, 3])
3

>>> len((1, 2, 3))
3

>>> len("abc")
3
```

!!! Add that a nested sequence will not return the count of elements within sequences

### min() and max()

```exercism/caution
Using `max()/max()` on an `string` is tricky since it compares via unicode code point value.
Therefore when dealing with characters outside of the English alphabet, the result may not be what you expect.
```

`min()` gives the minimum value in a sequence.

```python
>>> min([1, 2, 3])
1

>>> min("abc")
'a'
```

`max()` gives the maximum value in a sequence.

```python
>>> max([1, 2, 3])
3

>>> max("abc")
'c'
```

Using `max()/min()` on an empty sequence will raise a `ValueError`.

```python
>>> max([])

Traceback (most recent call last):
File "c:\sequence.py", line 3, in <module>
print(max([]))
^^^^^^^
ValueError: max() arg is an empty sequence
```

Using `min()/max()` on a sequence that includes a number and a `string` will raise a `TypeError`.

```python
>>> max([1, 2, 3, "a"])

Traceback (most recent call last):
File "c:\sequence.py", line 3, in <module>
print(max([1, 2, 3, "a"]))
^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: '>' not supported between instances of 'str' and 'int'
```

### Reverse a sequence

Using slicing with steps allows reversing a sequence.
That is because we can use a negative step to start at the end of the sequence and walk backwards.
This is a very common operation.

```python
>>> numbers = [1, 2, 3, 4, 5]
>>> numbers[::-1]
[5, 4, 3, 2, 1]

>>> name = "Delizald"
>>> name[::-1]
'dlazileD'
```

NOTES:

Time table, tickets, ads.
Models of trams

```python

def time_table(table_of_time, week_day, start, stop):
return table_of_time[week_day][start:stop]

print(time_table(("8:00", "9:00"),["8:00", "9:00"] ))
```

```python
def time_table(table_of_time, week_day, start, stop):
return table_of_time[week_day][start:stop]

print(time_table(("8:00", "9:00"),["8:00", "9:00"] ))
```

Fastest route (last exercise)

Fewest stops or transfers

Ad function

`min()`/`max()`, yes
`<sequence>.index`, yes
`<sequence>.count()`, maybe
`<sequence>.len()`, maybe
`slicing`, yes
`slice assignment`, yes
16 changes: 15 additions & 1 deletion concepts/sequences/introduction.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,16 @@
#TODO: Add introduction for this concept.
# Sequences

A sequence is an ordered, indexable collection of items.
All sequence types support a common set of operations that include `in`/`not in`, `min()`/`max()`, `<sequence>.index`, `<sequence>.count()` and `<sequence>.len()`.
`lists` support additional mutable operations such as [slice assignment][<url ref here>], `.append()`, `.extend()`, `.reverse()`, and `.copy()`.

All sequences can be indexed into using `<sequence>[<index number>]`, copied in whole or in part using `<sequence>[<start_index>:<stop_index>:<step>]`(_a full copy can be made with `<sequence>[:]`), and iterated over using the `for item in <sequence>` construct.
`for index, item in enumerate(<sequence>)` can be used when both the element index and the element value are needed.


Pythons `list`, `tuple`, `str`, `byte`, and `range` types all belong to this wider sequence type.
In the case of `str`, the “collection” is made up of unicode code points.
In the case of `byte`, bytes.
Ranges are “collections” of numbers conforming to a `start:stop:step` rule.


8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,14 @@
"name": "Locomotive Engineer",
"uuid": "e1b8b9c9-21c3-47b1-b645-5938b3110c78",
"concepts": ["unpacking-and-multiple-assignment"],
"prerequisites": ["loops", "lists", "tuples", "dicts", "unpacking-and-multiple-assignment"],
"status": "wip"
},
{
"slug": "thallias-tram-troubles",
"name": "Thallias Tram Troubles",
"uuid": "d1cf6301-d8fe-47a8-95a8-5ec0765aef7b",
"concepts": ["sequences"],
"prerequisites": ["loops", "lists", "tuples", "dicts"],
"status": "wip"
},
Expand Down
1 change: 1 addition & 0 deletions exercises/concept/thallias-tram-troubles/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hints
53 changes: 53 additions & 0 deletions exercises/concept/thallias-tram-troubles/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Instructions

Your classmate Thallia has just won an internship with the city's premier tram company.
Her goal for the term of the internship is to improve communications with the ridership and promote special services.
She's decided to focus on writing several apps that can run on station platforms, the tram website, and rider's phones.
Since writing all these apps is a big task, she's asked that the tram company recruit you to help with the project.

1. Schedules by Weekday Number

First on the agenda is an app that can help commuters navigate the various schedules so they can more easily get to and from work.
Thallia's got the lines and locations mostly figured out, but would like you to write a function that will filter the timetable sequence for a given weekday, so riders can clearly see all the departure times.
The aim will be to return tram departure times from the timetable based on a weekday number (_0 being Monday, 6 being Sunday_).
Write the `time_table_for_a_weekday` function that takes a nested sequence of timetables and weekday number.
It should return the schedule sequence corresponding to the weekday number.

```python
>>> time_table_for_a_weekday([["8:00", "17:00"], ("9:00", "16:00"), ("8:30", "15:00"), ["10:00", "19:00", "21:00"], ["12:00", "20:00"], ("9:00", "19:00"), ("9:30", "15:00", "20:00")], 3)
["10:00", "19:00", "21:00"]
```

2. Departures by Commute Window

Now that you have the weekday filtering figured out, Thallia has asked you to drill down into specific commute times.
This part of the app is designed to allow a commuter to input their commute day plus a "commute window" and receive a sequence of departure times.
With the `time_table_for_a_specific_range` function that takes a sequence of daily timetables, a weekday number, and `start`/`stop` indexes for the "commute window".
It should return a sequence of departure times for the commuter that fits their travel day and "commute window".

```python
>>> time_table_for_a_specific_range([["8:00", "17:00"], ("9:00", "16:00"), ("8:30", "15:00"), ["10:00", "19:00", "21:00"], ["12:00", "20:00"], ("9:00", "19:00"), ("9:30", "15:00", "20:00", "21:00")], 6, 1, 3)
("15:00", "20:00")
```

3. Calculate Route with Fewest Transfers

The tram system has many routes and many different ways for commuters to reach their destinations.
However, transferring adds time and complexity to the process.
Thallia is trying to tackle this in-app by asking you to add a feature that will calculate routes with the fewest transfers.

4. Calculate Fastest Route

To up the tram company's visibility, Thallia has decided to add functionality similar to Googles "plan a trip" functionality.
But instead of providing all routes and times, she'd like you to provide commuters only with the fastest available routes listed in the timetables.

5. Update Station Status Displays

Having built up commuter features, Thallia now wants to focus a bit on weekend "family activity" services.
She'd like to update the station display software to better promote different activities (concerts, museums, amusement parks, zoos, sports matches, theater) that can be reached via different tram lines.
She's asked you to write a function that will insert a short blurb about an activity into the arrival and departure displays.

6. Update Weekend Schedule Information

Thallia would also like to update the app so that weekend riders can know when an event is scheduled and what train departures will get them to the activities on time.
She'd like you to write a function that will insert an activity description and start time into a given schedule display, so that riders are reminded that they can take the tram to the activity.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#todo
10 changes: 10 additions & 0 deletions exercises/concept/thallias-tram-troubles/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"blurb": "todo",
"icon": "tracks-on-tracks-on-tracks",
"authors": ["meatball133","BethanyG"],
"files": {
"solution": ["sequences.py"],
"test": ["sequences_test.py"],
"exemplar": [".meta/exemplar.py"]
}
}
69 changes: 69 additions & 0 deletions exercises/concept/thallias-tram-troubles/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Design

## TODO: Add introduction for this concept.
## Goal

This concept exercise is meant to teach an understanding/use of `unpacking` and the `*` (splat) and `**` (double splat) operators in Python.

<br>

## Learning objectives

- Understand/use `unpacking` through the use of `*` and `**` _prefix_ operators in various scenarios
- `*` and `**` as _prefixes_ ..... not to be confused with `*` (_multiply_) and `**` (_exponentiation_) as _infix_, or mathematical operators (**consider a link in the links doc or a mention in dig deeper.**)
- ~~what happens in the process of "unpacking" - form, ordering, & iteration~~ (this will go in a **dig deeper** or the link docs.)
- use in arguments to `functions`
- use in argument _capture_ for `functions` (_aka passing an arbitrary number of arguments -- *args * & **kwargs_)
- ~~use in defining `keyword only arguments`~~ (_topic moved to arguments exercise_).
- use in iterable (_mainly `tuple` and `list`_) unpacking & packing
- use in `dict` unpacking & packing
- Understand/use `unpacking` via `multiple assignment`
- using `multiple assignment ` in place of `indexing`
- using `multiple assigment` + `*` in place of `slicing`
- ~~using "list-like" syntax & "tuple-like" syntax~~
- unpacking plus "leftovers" via `*`
- Differences between straight `multiple assignment` and `*` & `**`
- Deep unpacking


## Concepts

- `unpacking`
- `unpacking generalizations`
- `multiple assignment`


## Topics that are Out of scope

- `classes`
- `comprehensions`
- `comprehensions` in `lambdas`
- `map()`, `filter()` or `functools.reduce()` in a `comprehension`
- `function-arguments` beyond explaining briefly how `*`, `**` work in function arguments.
- `functools` beyond `functools.reduce()`(_this will get its own exercise_)
- `generators`
- using an `assignment expression` or "walrus" operator (`:=`) alone or in a `lambda`


## Prerequisites

- `basics`
- `bools`
- `comparisons`
- `dicts`
- `lists`
- `numbers`
- `strings`
- `tuples`


## Representer

This exercise does not require any specific logic to be added to the [representer][representer]

## Analyzer

This exercise does not require any specific logic to be added to the [analyzer][analyzer].

[analyzer]: https://github.com/exercism/python-analyzer
[representer]: https://github.com/exercism/python-representer
21 changes: 21 additions & 0 deletions exercises/concept/thallias-tram-troubles/.meta/exemplar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
def time_table_for_a_weekday(table_of_time, week_day):
"""Get the time table for a weekday.

:parm table_of_time: sequence[sequence] - sequence of time tables.
:parm week_day: integer - the number of the weekday.
:return: sequence - sequence of timetables within a weekday .
"""
return table_of_time[week_day]


def time_table_for_a_specific_range(table_of_time, week_day, start, stop):
"""Get the a slice of time table for a weekday.

:parm table_of_time: sequence[sequence] - sequence of time tables.
:parm week_day: integer - the number of the weekday.
:parm start: integer - the start of the slice.
:parm stop: integer - the end of the slice.
:return: sequence - slice of timetables within a weekday .
"""
return table_of_time[week_day][start:stop]

Loading