Afia B. answered 05/28/24
Expert AP CS & Programming Tutor | Java, C++, SQL, DLD, Linux,HTML,CSS
To solve the problem of calculating the tax for a list of individuals based on their yearly incomes according to a graduated tax scale, we can break down the problem into a function named calculate_tax
. This function will take a dictionary of names and incomes as input, compute the tax for each person based on the graduated scale, and return a dictionary with the names and their corresponding tax amounts.
Let's write the function calculate_tax
step-by-step and also include the test cases provided to ensure our function works correctly.
Step-by-Step Implementation
- Define the Tax Brackets and Rates: We'll create a list of tuples where each tuple contains the upper limit of a tax bracket and the corresponding tax rate.
- Iterate Over Each Person: For each person in the input dictionary, calculate their tax based on their income.
- Calculate Tax: For each income, iterate over the tax brackets and compute the tax for each segment of income falling within the brackets.
- Handle Edge Cases: Ensure the function handles edge cases such as non-numeric inputs and empty dictionaries.
- Return the Result: Return the computed taxes in the same dictionary format as the input.
Here's the code for calculate_tax
:
def calculate_tax(incomes):
if not isinstance(incomes, dict):
raise ValueError("The provided input is not a dictionary.")
tax_brackets = [
(1000, 0.00),
(10000, 0.10),
(20200, 0.15),
(30750, 0.20),
(50000, 0.25),
(float('inf'), 0.30)
]
result = {}
for name, income in incomes.items():
if not isinstance(income, (int, float)):
raise ValueError("Allow only numeric input")
tax = 0
previous_limit = 0
for limit, rate in tax_brackets:
if income > previous_limit:
taxable_income = min(income, limit) - previous_limit
tax += taxable_income * rate
previous_limit = limit
else:
break
result[name] = tax
return result
# Test cases
from unittest import TestCase
class CalculateTaxTests(TestCase):
def test_it_calculates_tax_for_one_person(self):
result = calculate_tax({"James": 20500})
self.assertEqual(result, {"James": 2490.0}, msg="Should return {'James': 2490.0} for the input {'James': 20500}")
def test_it_calculates_tax_for_several_people(self):
income_input = {"James": 20500, "Mary": 500, "Evan": 70000}
result = calculate_tax(income_input)
self.assertEqual({"James": 2490.0, "Mary": 0, "Evan": 15352.5}, result,
msg="Should return {} for the input {}".format(
{"James": 2490.0, "Mary": 0, "Evan": 15352.5},
{"James": 20500, "Mary": 500, "Evan": 70000}
)
)
def test_it_does_not_accept_integers(self):
with self.assertRaises(ValueError) as context:
calculate_tax(1)
self.assertEqual(
"The provided input is not a dictionary.",
str(context.exception), "Invalid input of type int not allowed"
)
def test_calculated_tax_is_a_float(self):
result = calculate_tax({"Jane": 20500})
self.assertIsInstance(
calculate_tax({"Jane": 20500}), dict, msg="Should return a result of data type dict")
self.assertIsInstance(result["Jane"], float, msg="Tax returned should be a float.")
def test_it_returns_zero_tax_for_income_less_than_1000(self):
result = calculate_tax({"Jake": 100})
self.assertEqual(result, {"Jake": 0}, msg="Should return zero tax for incomes less than 1000")
def test_it_throws_an_error_if_any_of_the_inputs_is_non_numeric(self):
with self.assertRaises(ValueError, msg='Allow only numeric input'):
calculate_tax({"James": 2490.0, "Kiura": '200', "Kinuthia": 15352.5})
def test_it_return_an_empty_dict_for_an_empty_dict_input(self):
result = calculate_tax({})
self.assertEqual(result, {}, msg='Should return an empty dict if the input was an empty dict')
Explanation:
-
Tax Brackets Definition: The
tax_brackets
list contains tuples of upper limits and their corresponding tax rates. - Input Validation: The function checks if the input is a dictionary and if all incomes are numeric.
- Tax Calculation: For each person, the function calculates the tax for each bracket and adds up the total tax.
- Handling Edge Cases: The function raises appropriate errors for invalid inputs and handles an empty input dictionary by returning an empty dictionary.
Running the Tests
The provided test cases can be used to validate the function using a testing framework such as unittest
. The function should pass all the test cases, ensuring it works as expected for different scenarios.