primeiro commit com exercicios de Exercism realizados até esta data
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"authors": [
|
||||
"mohanrajanr",
|
||||
"BethanyG"
|
||||
],
|
||||
"contributors": [
|
||||
"pranasziaukas"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"loops.py"
|
||||
],
|
||||
"test": [
|
||||
"loops_test.py"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.py"
|
||||
]
|
||||
},
|
||||
"icon": "grep",
|
||||
"blurb": "Learn about loops by grading and organizing your students exam scores."
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"track":"python","exercise":"making-the-grade","id":"ade6f1b3cf8e434fba3cb44e934d3d01","url":"https://exercism.org/tracks/python/exercises/making-the-grade","handle":"sanctushck","is_requester":true,"auto_approve":false}
|
||||
@@ -0,0 +1,130 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
We use [pytest][pytest: Getting Started Guide] as our website test runner.
|
||||
You will need to install `pytest` on your development machine if you want to run tests for the Python track locally.
|
||||
You should also install the following `pytest` plugins:
|
||||
|
||||
- [pytest-cache][pytest-cache]
|
||||
- [pytest-subtests][pytest-subtests]
|
||||
|
||||
Extended information can be found in our website [Python testing guide][Python track tests page].
|
||||
|
||||
|
||||
### Running Tests
|
||||
|
||||
To run the included tests, navigate to the folder where the exercise is stored using `cd` in your terminal (_replace `{exercise-folder-location}` below with your path_).
|
||||
Test files usually end in `_test.py`, and are the same tests that run on the website when a solution is uploaded.
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ cd {path/to/exercise-folder-location}
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> cd {path\to\exercise-folder-location}
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
Next, run the `pytest` command in your terminal, replacing `{exercise_test.py}` with the name of the test file:
|
||||
|
||||
Linux/MacOS
|
||||
```bash
|
||||
$ python3 -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
Windows
|
||||
```powershell
|
||||
PS C:\Users\foobar> py -m pytest -o markers=task {exercise_test.py}
|
||||
==================== 7 passed in 0.08s ====================
|
||||
```
|
||||
|
||||
|
||||
### Common options
|
||||
- `-o` : override default `pytest.ini` (_you can use this to avoid marker warnings_)
|
||||
- `-v` : enable verbose output.
|
||||
- `-x` : stop running tests on first failure.
|
||||
- `--ff` : run failures from previous test before running other test cases.
|
||||
|
||||
For additional options, use `python3 -m pytest -h` or `py -m pytest -h`.
|
||||
|
||||
|
||||
### Fixing warnings
|
||||
|
||||
If you do not use `pytest -o markers=task` when invoking `pytest`, you might receive a `PytestUnknownMarkWarning` for tests that use our new syntax:
|
||||
|
||||
```bash
|
||||
PytestUnknownMarkWarning: Unknown pytest.mark.task - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/stable/mark.html
|
||||
```
|
||||
|
||||
To avoid typing `pytest -o markers=task` for every test you run, you can use a `pytest.ini` configuration file.
|
||||
We have made one that can be downloaded from the top level of the Python track directory: [pytest.ini][pytest.ini].
|
||||
|
||||
You can also create your own `pytest.ini` file with the following content:
|
||||
|
||||
```ini
|
||||
[pytest]
|
||||
markers =
|
||||
task: A concept exercise task.
|
||||
```
|
||||
|
||||
Placing the `pytest.ini` file in the _root_ or _working_ directory for your Python track exercises will register the marks and stop the warnings.
|
||||
More information on pytest marks can be found in the `pytest` documentation on [marking test functions][pytest: marking test functions with attributes] and the `pytest` documentation on [working with custom markers][pytest: working with custom markers].
|
||||
|
||||
Information on customizing pytest configurations can be found in the `pytest` documentation on [configuration file formats][pytest: configuration file formats].
|
||||
|
||||
|
||||
### Extending your IDE or Code Editor
|
||||
|
||||
Many IDEs and code editors have built-in support for using `pytest` and other code quality tools.
|
||||
Some community-sourced options can be found on our [Python track tools page][Python track tools page].
|
||||
|
||||
[Pytest: Getting Started Guide]: https://docs.pytest.org/en/latest/getting-started.html
|
||||
[Python track tools page]: https://exercism.org/docs/tracks/python/tools
|
||||
[Python track tests page]: https://exercism.org/docs/tracks/python/tests
|
||||
[pytest-cache]:http://pythonhosted.org/pytest-cache/
|
||||
[pytest-subtests]:https://github.com/pytest-dev/pytest-subtests
|
||||
[pytest.ini]: https://github.com/exercism/python/blob/main/pytest.ini
|
||||
[pytest: configuration file formats]: https://docs.pytest.org/en/6.2.x/customize.html#configuration-file-formats
|
||||
[pytest: marking test functions with attributes]: https://docs.pytest.org/en/6.2.x/mark.html#raising-errors-on-unknown-marks
|
||||
[pytest: working with custom markers]: https://docs.pytest.org/en/6.2.x/example/markers.html#working-with-custom-markers
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit loops.py` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Python track's documentation](https://exercism.org/docs/tracks/python)
|
||||
- The [Python track's programming category on the forum](https://forum.exercism.org/c/programming/python)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Below are some resources for getting help if you run into trouble:
|
||||
|
||||
- [The PSF](https://www.python.org) hosts Python downloads, documentation, and community resources.
|
||||
- [The Exercism Community on Discord](https://exercism.org/r/discord)
|
||||
- [Python Community on Discord](https://pythondiscord.com/) is a very helpful and active community.
|
||||
- [/r/learnpython/](https://www.reddit.com/r/learnpython/) is a subreddit designed for Python learners.
|
||||
- [#python on Libera.chat](https://www.python.org/community/irc/) this is where the core developers for the language hang out and get work done.
|
||||
- [Python Community Forums](https://discuss.python.org/)
|
||||
- [Free Code Camp Community Forums](https://forum.freecodecamp.org/)
|
||||
- [CodeNewbie Community Help Tag](https://community.codenewbie.org/t/help)
|
||||
- [Pythontutor](http://pythontutor.com/) for stepping through small code snippets visually.
|
||||
|
||||
Additionally, [StackOverflow](http://stackoverflow.com/questions/tagged/python) is a good spot to search for your problem/question to see if it has been answered already.
|
||||
If not - you can always [ask](https://stackoverflow.com/help/how-to-ask) or [answer](https://stackoverflow.com/help/how-to-answer) someone else's question.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- [`while`][while-loops] loops are used for _indefinite_ (uncounted) iteration
|
||||
- [`for`][for-loops] loops are used for _definite_, (counted) iteration.
|
||||
- The keywords [`break` and `continue`][control flow] help customize loop behavior.
|
||||
- [`range(<start>, stop, <step>)`][range] can be used to generate a sequence for a loop counter.
|
||||
- The built-in [`enumerate()`][enumerate] will return (`<value>`, `<index>`) pairs to iterate over.
|
||||
|
||||
Also being familiar with the following can help with completing the tasks:
|
||||
|
||||
- [`lists`][list]: indexing, nested lists, [`<list>.append`][append and pop], [`<list>.pop()`][append and pop].
|
||||
- [`str`][str]: `str()` constructor, using the `+` to concatenate strings, optionally, [`f-strings`][f-strings].
|
||||
|
||||
## 1. Rounding Scores
|
||||
|
||||
- `While` loops will continue to execute until their test condition evaluates to `False`.
|
||||
- `<list>.pop()` will remove and return the last item in a `list`.
|
||||
- Empty lists evaluate to `False` (most empty objects in Python are "Falsy")
|
||||
|
||||
## 2. Non-Passing Students
|
||||
|
||||
- There's no need to declare `loop` counters or `index` counters when iterating through an object using a `for` loop.
|
||||
- A results counter does need to be set up and _incremented_ -- you'll want to `return` the count of non-passing students when the loop terminates.
|
||||
|
||||
## 3. The "Best"
|
||||
|
||||
- There's no need to declare `loop` counters or `index` counters when iterating through an object using a `for` loop.
|
||||
- Having an empty `list` to add the "best" marks to is helpful here.
|
||||
- `<list>.append()` can help add things to the results `list`.
|
||||
|
||||
## 4. Calculating Letter Grades
|
||||
|
||||
- These are _lower thresholds_. The _lower threshold_ for a "D" is a score of **41**, since an "F" is **<= 40**.
|
||||
- [`range()`][range] can be helpful here to generate a sequence with the proper "F" -> "A" increments.
|
||||
- [`round()`][round] without parameters should round off increments nicely.
|
||||
- As with "the best" task, `<list>.append()` could be useful here to append items from `range()` into a results `list`.
|
||||
|
||||
## 5. Matching Names to Scores
|
||||
|
||||
- [`enumerate()`][enumerate] could be helpful here.
|
||||
- If both lists are the same length and sorted the same way, could you use the `index` from one to retrieve a `value` from the other?
|
||||
|
||||
## 6. A "Perfect" Score
|
||||
|
||||
- There may be or may not be a student with a score of 100, and you can't return `[]` without checking **all** scores.
|
||||
- The [`control flow`][control flow] statements `continue` and `break` may be useful here to move past unwanted values.
|
||||
|
||||
[append and pop]: https://docs.python.org/3/tutorial/datastructures.html#more-on-lists
|
||||
[control flow]: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops
|
||||
[enumerate]: https://docs.python.org/3/library/functions.html#enumerate
|
||||
[f-strings]: https://docs.python.org/3/reference/lexical_analysis.html#formatted-string-literals
|
||||
[for-loops]: https://docs.python.org/3/tutorial/controlflow.html#for-statements
|
||||
[list]: https://docs.python.org/3/library/stdtypes.html#list
|
||||
[range]: https://docs.python.org/3/tutorial/controlflow.html#the-range-function
|
||||
[round]: https://docs.python.org/3/library/functions.html#round
|
||||
[str]: https://docs.python.org/3/library/stdtypes.html#str
|
||||
[while-loops]: https://docs.python.org/3/reference/compound_stmts.html#the-while-statement
|
||||
@@ -0,0 +1,321 @@
|
||||
# Making the Grade
|
||||
|
||||
Welcome to Making the Grade on Exercism's Python Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
Python has two looping constructs.
|
||||
`while` loops for _indefinite_ (uncounted) iteration and `for` loops for _definite_, (counted) iteration.
|
||||
The keywords `break`, `continue`, and `else` help customize loop behavior.
|
||||
`range()` and `enumerate()` help with loop counting and indexing.
|
||||
|
||||
|
||||
## While
|
||||
|
||||
[`while`][while statement] loops will continue to execute as long as the `loop expression` or "test" evaluates to `True` in a [`boolean context`][truth value testing], terminating when it evaluates to `False`:
|
||||
|
||||
```python
|
||||
|
||||
# Lists are considered "truthy" in a boolean context if they
|
||||
# contain one or more values, and "falsy" if they are empty.
|
||||
|
||||
>>> placeholders = ["spam", "ham", "eggs", "green_spam", "green_ham", "green_eggs"]
|
||||
|
||||
>>> while placeholders:
|
||||
... print(placeholders.pop(0))
|
||||
...
|
||||
'spam'
|
||||
'ham'
|
||||
'eggs'
|
||||
'green_spam'
|
||||
'green_ham'
|
||||
'green_eggs'
|
||||
```
|
||||
|
||||
|
||||
## For
|
||||
|
||||
The basic [`for`][for statement] `loop` in Python is better described as a _`for each`_ which cycles through the values of any [iterable object][iterable], terminating when there are no values returned from calling [`next()`][next built-in]:
|
||||
|
||||
```python
|
||||
|
||||
>>> word_list = ["bird", "chicken", "barrel", "bongo"]
|
||||
|
||||
>>> for word in word_list:
|
||||
... if word.startswith("b"):
|
||||
... print(f"{word.title()} starts with a B.")
|
||||
... else:
|
||||
... print(f"{word.title()} doesn't start with a B.")
|
||||
...
|
||||
'Bird starts with a B.'
|
||||
'Chicken doesn\'t start with a B.'
|
||||
'Barrel starts with a B.'
|
||||
'Bongo starts with a B.'
|
||||
```
|
||||
|
||||
|
||||
## Sequence Object range()
|
||||
|
||||
When there isn't a specific `iterable` given, the special [`range()`][range] sequence is used as a loop counter.
|
||||
`range()` requires an `int` before which to `stop` the sequence, and can optionally take `start` and `step` parameters.
|
||||
If no `start` number is provided, the sequence will begin with 0.
|
||||
`range()` objects are **lazy** (_values are generated on request_), support all [common sequence operations][common sequence operations], and take up a fixed amount of memory, no matter how long the sequence specified.
|
||||
|
||||
```python
|
||||
# Here we use range to produce some numbers, rather than creating a list of them in memory.
|
||||
# The values will start with 1 and stop *before* 7
|
||||
|
||||
>>> for number in range(1, 7):
|
||||
... if number % 2 == 0:
|
||||
... print(f"{number} is even.")
|
||||
... else:
|
||||
... print(f"{number} is odd.")
|
||||
'1 is odd.'
|
||||
'2 is even.'
|
||||
'3 is odd.'
|
||||
'4 is even.'
|
||||
'5 is odd.'
|
||||
'6 is even.'
|
||||
|
||||
# range() can also take a *step* parameter.
|
||||
# Here we use range to produce only the "odd" numbers, starting with 3 and stopping *before* 15.
|
||||
|
||||
>>> for number in range(3, 15, 2):
|
||||
... if number % 2 == 0:
|
||||
... print(f"{number} is even.")
|
||||
... else:
|
||||
... print(f"{number} is odd.")
|
||||
...
|
||||
'3 is odd.'
|
||||
'5 is odd.'
|
||||
'7 is odd.'
|
||||
'9 is odd.'
|
||||
'11 is odd.'
|
||||
'13 is odd.'
|
||||
```
|
||||
|
||||
|
||||
## Values and Indexes with enumerate()
|
||||
|
||||
If both values and their indexes are needed, the built-in [`enumerate(<iterable>)`][enumerate] will return (`index`, `value`) pairs:
|
||||
|
||||
```python
|
||||
|
||||
>>> word_list = ["bird", "chicken", "barrel", "apple"]
|
||||
|
||||
# *index* and *word* are the loop variables.
|
||||
# Loop variables can be any valid python name.
|
||||
|
||||
>>> for index, word in enumerate(word_list):
|
||||
... if word.startswith("b"):
|
||||
... print(f"{word.title()} (at index {index}) starts with a B.")
|
||||
... else:
|
||||
... print(f"{word.title()} (at index {index}) doesn't start with a B.")
|
||||
...
|
||||
'Bird (at index 0) starts with a B.'
|
||||
'Chicken (at index 1) doesn\'t start with a B.'
|
||||
'Barrel (at index 2) starts with a B.'
|
||||
'Apple (at index 3) doesn\'t start with a B.'
|
||||
|
||||
|
||||
# The same method can be used as a "lookup" for pairing items between two lists.
|
||||
# Of course, if the lengths or indexes don't line up, this doesn't work.
|
||||
|
||||
>>> word_list = ["cat", "chicken", "barrel", "apple", "spinach"]
|
||||
>>> category_list = ["mammal", "bird", "thing", "fruit", "vegetable"]
|
||||
|
||||
>>> for index, word in enumerate(word_list):
|
||||
... print(f"{word.title()} is in category: {category_list[index]}.")
|
||||
...
|
||||
'Cat is in category: mammal.'
|
||||
'Chicken is in category: bird.'
|
||||
'Barrel is in category: thing.'
|
||||
'Apple is in category: fruit.'
|
||||
'Spinach is in category: vegetable.'
|
||||
```
|
||||
|
||||
|
||||
## Altering Loop Behavior
|
||||
|
||||
The [`continue`][continue statement] keyword can be used to skip forward to the next iteration cycle:
|
||||
|
||||
```python
|
||||
word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple", "bear"]
|
||||
|
||||
# This will skip *bird*, at index 0
|
||||
for index, word in enumerate(word_list):
|
||||
if index == 0:
|
||||
continue
|
||||
if word.startswith("b"):
|
||||
print(f"{word.title()} (at index {index}) starts with a b.")
|
||||
|
||||
'Barrel (at index 2) starts with a b.'
|
||||
'Bongo (at index 3) starts with a b.'
|
||||
'Bear (at index 6) starts with a b.'
|
||||
```
|
||||
|
||||
|
||||
The [`break`][break statement] (_like in many C-related languages_) keyword can be used to stop the iteration and "break out" of the innermost enclosing `loop`:
|
||||
|
||||
```python
|
||||
>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple"]
|
||||
|
||||
>>> for index, word in enumerate(word_list):
|
||||
... if word.startswith("b"):
|
||||
... print(f"{word.title()} (at index {index}) starts with a B.")
|
||||
... elif word == "sliver":
|
||||
... break
|
||||
... else:
|
||||
... print(f"{word.title()} doesn't start with a B.")
|
||||
... print("loop broken.")
|
||||
...
|
||||
'Bird (at index 0) starts with a B.'
|
||||
'Chicken doesn\'t start with a B.'
|
||||
'Barrel (at index 2) starts with a B.'
|
||||
'Bongo (at index 3) starts with a B.'
|
||||
'loop broken.'
|
||||
```
|
||||
|
||||
[break statement]: https://docs.python.org/3/reference/simple_stmts.html#the-break-statement
|
||||
[common sequence operations]: https://docs.python.org/3/library/stdtypes.html#common-sequence-operations
|
||||
[continue statement]: https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement
|
||||
[enumerate]: https://docs.python.org/3/library/functions.html#enumerate
|
||||
[for statement]: https://docs.python.org/3/reference/compound_stmts.html#for
|
||||
[iterable]: https://docs.python.org/3/glossary.html#term-iterable
|
||||
[next built-in]: https://docs.python.org/3/library/functions.html#next
|
||||
[range]: https://docs.python.org/3/library/stdtypes.html#range
|
||||
[truth value testing]: https://docs.python.org/3/library/stdtypes.html#truth-value-testing
|
||||
[while statement]: https://docs.python.org/3/reference/compound_stmts.html#the-while-statement
|
||||
|
||||
## Instructions
|
||||
|
||||
You're a teaching assistant correcting student exams.
|
||||
Keeping track of results manually is getting both tedious and mistake-prone.
|
||||
You decide to make things a little more interesting by putting together some functions to count and calculate results for the class.
|
||||
|
||||
## 1. Rounding Scores
|
||||
|
||||
While you can give "partial credit" on exam questions, overall exam scores have to be `int`s.
|
||||
So before you can do anything else with the class scores, you need to go through the grades and turn any `float` scores into `int`s. Lucky for you, Python has the built-in [`round()`][round] function you can use.
|
||||
|
||||
Create the function `round_scores(student_scores)` that takes a `list` of `student_scores`.
|
||||
This function should _consume_ the input `list` and `return` a new list with all the scores converted to `int`s.
|
||||
The order of the scores in the resulting `list` is not important.
|
||||
|
||||
```python
|
||||
>>> student_scores = [90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3]
|
||||
>>> round_scores(student_scores)
|
||||
...
|
||||
[40, 39, 95, 80, 25, 31, 70, 55, 40, 90]
|
||||
```
|
||||
|
||||
## 2. Non-Passing Students
|
||||
|
||||
As you were grading the exam, you noticed some students weren't performing as well as you had hoped.
|
||||
But you were distracted, and forgot to note exactly _how many_ students.
|
||||
|
||||
Create the function `count_failed_students(student_scores)` that takes a `list` of `student_scores`.
|
||||
This function should count up the number of students who don't have passing scores and return that count as an integer.
|
||||
A student needs a score greater than **40** to achieve a passing grade on the exam.
|
||||
|
||||
```python
|
||||
>>> count_failed_students(student_scores=[90,40,55,70,30,25,80,95,38,40])
|
||||
5
|
||||
```
|
||||
|
||||
## 3. The "Best"
|
||||
|
||||
The teacher you're assisting wants to find the group of students who've performed "the best" on this exam.
|
||||
What qualifies as "the best" fluctuates, so you need to find the student scores that are **greater than or equal to** the current threshold.
|
||||
|
||||
Create the function `above_threshold(student_scores, threshold)` taking `student_scores` (a `list` of grades), and `threshold` (the "top score" threshold) as parameters.
|
||||
This function should return a `list` of all scores that are `>=` to `threshold`.
|
||||
|
||||
```python
|
||||
>>> above_threshold(student_scores=[90,40,55,70,30,68,70,75,83,96], threshold=75)
|
||||
[90,75,83,96]
|
||||
```
|
||||
|
||||
## 4. Calculating Letter Grades
|
||||
|
||||
The teacher you are assisting likes to assign letter grades as well as numeric scores.
|
||||
Since students rarely score 100 on an exam, the "letter grade" lower thresholds are calculated based on the highest score achieved, and increment evenly between the high score and the failing threshold of **<= 40**.
|
||||
|
||||
Create the function `letter_grades(highest)` that takes the "highest" score on the exam as an argument, and returns a `list` of lower score thresholds for each "American style" grade interval: `["D", "C", "B", "A"]`.
|
||||
|
||||
|
||||
```python
|
||||
"""Where the highest score is 100, and failing is <= 40.
|
||||
"F" <= 40
|
||||
41 <= "D" <= 55
|
||||
56 <= "C" <= 70
|
||||
71 <= "B" <= 85
|
||||
86 <= "A" <= 100
|
||||
"""
|
||||
|
||||
>>> letter_grades(highest=100)
|
||||
[41, 56, 71, 86]
|
||||
|
||||
|
||||
"""Where the highest score is 88, and failing is <= 40.
|
||||
"F" <= 40
|
||||
41 <= "D" <= 52
|
||||
53 <= "C" <= 64
|
||||
65 <= "B" <= 76
|
||||
77 <= "A" <= 88
|
||||
"""
|
||||
|
||||
>>> letter_grades(highest=88)
|
||||
[41, 53, 65, 77]
|
||||
```
|
||||
|
||||
## 5. Matching Names to Scores
|
||||
|
||||
You have a list of exam scores in descending order, and another list of student names also sorted in descending order by their exam scores.
|
||||
You would like to match each student name with their exam score and print out an overall class ranking.
|
||||
|
||||
Create the function `student_ranking(student_scores, student_names)` with parameters `student_scores` and `student_names`.
|
||||
Match each student name on the student_names `list` with their score from the student_scores `list`.
|
||||
You can assume each argument `list` will be sorted from highest score(er) to lowest score(er).
|
||||
The function should return a `list` of strings with the format `<rank>. <student name>: <student score>`.
|
||||
|
||||
```python
|
||||
>>> student_scores = [100, 99, 90, 84, 66, 53, 47]
|
||||
>>> student_names = ['Joci', 'Sara','Kora','Jan','John','Bern', 'Fred']
|
||||
>>> student_ranking(student_scores, student_names)
|
||||
...
|
||||
['1. Joci: 100', '2. Sara: 99', '3. Kora: 90', '4. Jan: 84', '5. John: 66', '6. Bern: 53', '7. Fred: 47']
|
||||
```
|
||||
|
||||
## 6. A "Perfect" Score
|
||||
|
||||
Although a "perfect" score of 100 is rare on an exam, it is interesting to know if at least one student has achieved it.
|
||||
|
||||
Create the function `perfect_score(student_info)` with parameter `student_info`.
|
||||
`student_info` is a `list` of lists containing the name and score of each student: `[["Charles", 90], ["Tony", 80]]`.
|
||||
The function should `return` _the first_ `[<name>, <score>]` pair of the student who scored 100 on the exam.
|
||||
|
||||
If no 100 scores are found in `student_info`, an empty list `[]` should be returned.
|
||||
|
||||
```python
|
||||
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80], ["Alex", 100]])
|
||||
["Alex", 100]
|
||||
|
||||
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80]])
|
||||
[]
|
||||
```
|
||||
|
||||
[round]: https://docs.python.org/3/library/functions.html#round
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @mohanrajanr
|
||||
- @BethanyG
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @pranasziaukas
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,88 @@
|
||||
"""Functions for organizing and calculating student exam scores."""
|
||||
|
||||
|
||||
def round_scores(student_scores):
|
||||
"""Round all provided student scores.
|
||||
|
||||
:param student_scores: list - float or int of student exam scores.
|
||||
:return: list - student scores *rounded* to nearest integer value.
|
||||
"""
|
||||
rounded_scores: list = []
|
||||
for score in student_scores:
|
||||
rounded_scores.append(round(score))
|
||||
return rounded_scores
|
||||
|
||||
|
||||
def count_failed_students(student_scores):
|
||||
"""Count the number of failing students out of the group provided.
|
||||
|
||||
:param student_scores: list - containing int student scores.
|
||||
:return: int - count of student scores at or below 40.
|
||||
"""
|
||||
number_failed_students: int = 0
|
||||
for score in student_scores:
|
||||
if score <= 40:
|
||||
number_failed_students += 1
|
||||
return number_failed_students
|
||||
|
||||
|
||||
def above_threshold(student_scores, threshold):
|
||||
"""Determine how many of the provided student scores were 'the best' based on the provided threshold.
|
||||
|
||||
:param student_scores: list - of integer scores.
|
||||
:param threshold: int - threshold to cross to be the "best" score.
|
||||
:return: list - of integer scores that are at or above the "best" threshold.
|
||||
"""
|
||||
above_the_best: list = []
|
||||
for score in student_scores:
|
||||
if score >= threshold:
|
||||
above_the_best.append(score)
|
||||
return above_the_best
|
||||
|
||||
|
||||
def letter_grades(highest):
|
||||
"""Create a list of grade thresholds based on the provided highest grade.
|
||||
|
||||
:param highest: int - value of highest exam score.
|
||||
:return: list - of lower threshold scores for each D-A letter grade interval.
|
||||
For example, where the highest score is 100, and failing is <= 40,
|
||||
The result would be [41, 56, 71, 86]:
|
||||
|
||||
41 <= "D" <= 55
|
||||
56 <= "C" <= 70
|
||||
71 <= "B" <= 85
|
||||
86 <= "A" <= 100
|
||||
"""
|
||||
diff_between_levels: int = round((highest - 41) / 4)
|
||||
scores_letter_grades: list = []
|
||||
for level in range(0, 4):
|
||||
scores_letter_grades.append(41 + (level * diff_between_levels))
|
||||
return scores_letter_grades
|
||||
|
||||
|
||||
def student_ranking(student_scores, student_names):
|
||||
"""Organize the student's rank, name, and grade information in descending order.
|
||||
|
||||
:param student_scores: list - of scores in descending order.
|
||||
:param student_names: list - of string names by exam score in descending order.
|
||||
:return: list - of strings in format ["<rank>. <student name>: <score>"].
|
||||
"""
|
||||
name_and_score: list = [
|
||||
f"{rank}. {name}: {score}"
|
||||
for rank, (name, score) in enumerate(
|
||||
zip(student_names, student_scores), start=1
|
||||
)
|
||||
]
|
||||
return name_and_score
|
||||
|
||||
|
||||
def perfect_score(student_info):
|
||||
"""Create a list that contains the name and grade of the first student to make a perfect score on the exam.
|
||||
|
||||
:param student_info: list - of [<student name>, <score>] lists.
|
||||
:return: list - first `[<student name>, 100]` or `[]` if no student score of 100 is found.
|
||||
"""
|
||||
for name, score in student_info:
|
||||
if score == 100:
|
||||
return [name, score]
|
||||
return []
|
||||
@@ -0,0 +1,226 @@
|
||||
import unittest
|
||||
import pytest
|
||||
from loops import (
|
||||
round_scores,
|
||||
count_failed_students,
|
||||
above_threshold,
|
||||
letter_grades,
|
||||
student_ranking,
|
||||
perfect_score,
|
||||
)
|
||||
|
||||
|
||||
class MakingTheGradeTest(unittest.TestCase):
|
||||
@pytest.mark.task(taskno=1)
|
||||
def test_round_scores(self):
|
||||
# Because we the input list can be mutated, the test data has been created
|
||||
# as tuples, which we then convert to a list when the test runs.
|
||||
# this makes accurate error messages easier to create.
|
||||
test_data = [
|
||||
tuple(),
|
||||
(0.5,),
|
||||
(1.5,),
|
||||
(90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3),
|
||||
(50, 36.03, 76.92, 40.7, 43, 78.29, 63.58, 91, 28.6, 88.0),
|
||||
]
|
||||
result_data = [
|
||||
[],
|
||||
[0],
|
||||
[2],
|
||||
[90, 40, 55, 70, 31, 25, 80, 95, 39, 40],
|
||||
[50, 36, 77, 41, 43, 78, 64, 91, 29, 88],
|
||||
]
|
||||
|
||||
for variant, (student_scores, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}",
|
||||
student_scores=student_scores,
|
||||
expected=expected,
|
||||
):
|
||||
# Because the test_input is a tuple, it has to be converted to a list for the function call.
|
||||
actual_result = round_scores(list(student_scores))
|
||||
error_message = (
|
||||
f"Called round_scores({list(student_scores)}). "
|
||||
f"The function returned {sorted(actual_result)} after sorting, but "
|
||||
f"the tests expected {sorted(expected)} after sorting. "
|
||||
f"One or more scores were rounded incorrectly."
|
||||
)
|
||||
|
||||
# everything is sorted for easier comparison.
|
||||
self.assertEqual(
|
||||
sorted(actual_result), sorted(expected), msg=error_message
|
||||
)
|
||||
|
||||
@pytest.mark.task(taskno=2)
|
||||
def test_count_failed_students(self):
|
||||
test_data = [
|
||||
[89, 85, 42, 57, 90, 100, 95, 48, 70, 96],
|
||||
[40, 40, 35, 70, 30, 41, 90],
|
||||
]
|
||||
result_data = [0, 4]
|
||||
|
||||
for variant, (student_scores, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}",
|
||||
student_scores=student_scores,
|
||||
expected=expected,
|
||||
):
|
||||
actual_result = count_failed_students(student_scores)
|
||||
error_message = (
|
||||
f"Called count_failed_students({student_scores}). "
|
||||
f"The function returned {actual_result}, but "
|
||||
f"the tests expected {expected} for the "
|
||||
"number of students who failed."
|
||||
)
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=3)
|
||||
def test_above_threshold(self):
|
||||
test_data = [
|
||||
([40, 39, 95, 80, 25, 31, 70, 55, 40, 90], 98),
|
||||
([88, 29, 91, 64, 78, 43, 41, 77, 36, 50], 80),
|
||||
([100, 89], 100),
|
||||
([88, 29, 91, 64, 78, 43, 41, 77, 36, 50], 78),
|
||||
([], 80),
|
||||
]
|
||||
|
||||
result_data = [[], [88, 91], [100], [88, 91, 78], []]
|
||||
|
||||
for variant, (params, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}", params=params, expected=expected
|
||||
):
|
||||
actual_result = above_threshold(*params)
|
||||
error_message = (
|
||||
f"Called above_threshold{params}. "
|
||||
f"The function returned {actual_result}, but "
|
||||
f"the tests expected {expected} for the "
|
||||
"scores that are above the threshold."
|
||||
)
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=4)
|
||||
def test_letter_grades(self):
|
||||
test_data = [100, 97, 85, 92, 81]
|
||||
|
||||
result_data = [
|
||||
[41, 56, 71, 86],
|
||||
[41, 55, 69, 83],
|
||||
[41, 52, 63, 74],
|
||||
[41, 54, 67, 80],
|
||||
[41, 51, 61, 71],
|
||||
]
|
||||
|
||||
for variant, (highest, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}", highest=highest, expected=expected
|
||||
):
|
||||
actual_result = letter_grades(highest)
|
||||
error_message = (
|
||||
f"Called letter_grades({highest}). "
|
||||
f"The function returned {actual_result}, but "
|
||||
f"the tests expected {expected} for the "
|
||||
"letter grade cutoffs."
|
||||
)
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=5)
|
||||
def test_student_ranking(self):
|
||||
test_data = [
|
||||
([82], ["Betty"]),
|
||||
([88, 73], ["Paul", "Ernest"]),
|
||||
(
|
||||
[100, 98, 92, 86, 70, 68, 67, 60],
|
||||
["Rui", "Betty", "Joci", "Yoshi", "Kora", "Bern", "Jan", "Rose"],
|
||||
),
|
||||
]
|
||||
|
||||
result_data = [
|
||||
["1. Betty: 82"],
|
||||
["1. Paul: 88", "2. Ernest: 73"],
|
||||
[
|
||||
"1. Rui: 100",
|
||||
"2. Betty: 98",
|
||||
"3. Joci: 92",
|
||||
"4. Yoshi: 86",
|
||||
"5. Kora: 70",
|
||||
"6. Bern: 68",
|
||||
"7. Jan: 67",
|
||||
"8. Rose: 60",
|
||||
],
|
||||
]
|
||||
|
||||
for variant, (params, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}", params=params, expected=expected
|
||||
):
|
||||
actual_result = student_ranking(*params)
|
||||
error_message = (
|
||||
f"Called student_ranking{params}. "
|
||||
f"The function returned {actual_result}, but "
|
||||
f"the tests expected {expected} for the "
|
||||
"student rankings."
|
||||
)
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
|
||||
@pytest.mark.task(taskno=6)
|
||||
def test_perfect_score(self):
|
||||
test_data = [
|
||||
[["Joci", 100], ["Vlad", 100], ["Raiana", 100], ["Alessandro", 100]],
|
||||
[["Jill", 30], ["Paul", 73]],
|
||||
[],
|
||||
[
|
||||
["Rui", 60],
|
||||
["Joci", 58],
|
||||
["Sara", 91],
|
||||
["Kora", 93],
|
||||
["Alex", 42],
|
||||
["Jan", 81],
|
||||
["Lilliana", 40],
|
||||
["John", 60],
|
||||
["Bern", 28],
|
||||
["Vlad", 55],
|
||||
],
|
||||
[
|
||||
["Yoshi", 52],
|
||||
["Jan", 86],
|
||||
["Raiana", 100],
|
||||
["Betty", 60],
|
||||
["Joci", 100],
|
||||
["Kora", 81],
|
||||
["Bern", 41],
|
||||
["Rose", 94],
|
||||
],
|
||||
]
|
||||
|
||||
result_data = [["Joci", 100], [], [], [], ["Raiana", 100]]
|
||||
|
||||
for variant, (student_info, expected) in enumerate(
|
||||
zip(test_data, result_data), start=1
|
||||
):
|
||||
with self.subTest(
|
||||
f"variation #{variant}", student_info=student_info, expected=expected
|
||||
):
|
||||
actual_result = perfect_score(student_info)
|
||||
error_message = (
|
||||
f"Called perfect_score({student_info}). "
|
||||
f"The function returned {actual_result}, but "
|
||||
f"the tests expected {expected} for the "
|
||||
'first "perfect" score.'
|
||||
)
|
||||
|
||||
self.assertEqual(actual_result, expected, msg=error_message)
|
||||
Reference in New Issue
Block a user