---
jupyter:
jupytext:
text_representation:
extension: .md
format_name: markdown
format_version: '1.1'
jupytext_version: 1.1.0-rc0
kernelspec:
display_name: Python 3
language: python
name: python3
---
```raw_mimetype="text/restructuredtext"
.. meta::
:description: Topic: Within Margin Exercise, Difficulty: Medium, Category: Practice Problem
:keywords: function, control flow, comparisons, practice problem
```
# Within Margin Percentage
>An algorithm is required to test out what percentage of the parts that a factory is producing fall within a safety margin of the design specifications. Given a list of values recording the metrics of the manufactured parts, a list of values representing the desired metrics required by the design, and a margin of error allowed by the design, compute what fraction of the values are within the safety margin (`<=`)
``` Python
# example behavior
>>> within_margin_percentage(desired=[10.0, 5.0, 8.0, 3.0, 2.0],
... actual= [10.3, 5.2, 8.4, 3.0, 1.2],
... margin=0.5)
0.8
```
See that $4/5$ of the values fall within the margin of error: $1.2$ deviates from $2$ by more than $0.5$.
Complete the following function; consider the edge case where `desired` and `actual` are empty lists.
```python
def within_margin_percentage(desired, actual, margin):
""" Compute the percentage of values that fall within
a margin of error of the desired values
Parameters
----------
desired: List[float]
The desired metrics
actual: List[float]
The corresponding actual metrics.
Assume `len(actual) == len(desired)`
margin: float
The allowed margin of error
Returns
-------
float
The fraction of values where |actual - desired| <= margin
"""
# YOUR CODE HERE
pass
```
You will want to be familiar with [comparison operators](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/ConditionalStatements.html#Comparison-Operations), [control flow](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Introduction.html), and [indexing lists](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/SequenceTypes.html#Introducing-Indexing-and-Slicing) lists to solve this problem.
## Solution
This problem can solved by simply looping over the pairs of actual and desired values and tallying the pairs that fall within the margin:
``` Python
def within_margin_percentage(desired, actual, margin):
""" Compute the percentage of values that fall within
a margin of error of the desired values
Parameters
----------
desired: List[float]
The desired metrics
actual: List[float]
The actual metrics
margin: float
The allowed margin of error
Returns
-------
float
The fraction of values where |actual - desired| <= margin
"""
count = 0 # tally of how values are within margin
total = len(desired)
for i in range(total):
if abs(desired[i] - actual[i]) <= margin:
count += 1 # Equivalent to `count = count + 1`
return count / total if total > 0 else 1.0
```
See that we handle the edge case where `desired` and `actual` are empty lists: the [inline if-else statement](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/ConditionalStatements.html#Inline-if-else-statements) `count / total if total > 0 else 1` will return `1` when `total` is 0:
```python
>>> within_margin_percentage([], [], margin=0.5)
1.0
```
which is arguably the appropriate behavior for this scenario (no values fall outside of the margin). Had we not anticipated this edge case, `within_margin_percentage([], [], margin=0.5)` would raise `ZeroDivisionError`.
It is also possible to write this solution using the built-in `sum` function and a [generator comprehension](https://www.pythonlikeyoumeanit.com/Module2_EssentialsOfPython/Generators_and_Comprehensions.html#Creating-your-own-generator:-generator-comprehensions) that filters out those pairs of items that fall outside of the desired margin:
```python
def within_margin_percentage(desired, actual, margin):
total = len(desired)
count = sum(1 for i in range(total) if abs(actual[i] - desired[i]) <= margin)
return count / total if total > 0 else 1.0
```
It is debatable whether this refactored solution is superior to the original one - it depends largely on how comfortable you, and anyone else who will be reading your code, are with the generator comprehension syntax.