How do I use dictionary to replace long if else block? - python

I'm writing an income tax calculator for 2017. Right now for calculating Federal taxes I have a long if else block:
def taxes(income):
"""Calculate income tax brackets from 10% to 39.6%"""
if 0 < income <= 9325:
return income * 0.1
elif income <= 37950:
return 932.5 + .15 * (income - 9325)
elif income <= 91900:
return 5226.25 + .25 * (income - 37950)
elif income <= 191650:
return 18713.75 + .28 * (income - 91900)
elif income <= 416700:
return 46643.75 + .33 * (income - 191650)
elif income <= 418400:
return 120910.25 + .35 * (income - 416700)
else:
return 121505.25 + .396 * (income - 418400)
I found in some other posts that I can use dictionary to access the values directly with dict.get(key, default). But in my case it's a bit different since I'm comparing income in a range of tax brackets and doing calculations with the income. Is there a way for me to use dictionary to simulate the if else block?

By using lambda functions and the thresholds in your if-else statements, you could do:
TAX_DICT = {
0: lambda income: income * 0.1,
9325: lambda income: 932.5 + .15 * (income - 9325),
37950: lambda income: 5226.25 + .25 * (income - 37950),
91900: lambda income: 18713.75 + .28 * (income - 91900),
191650: lambda income: 46643.75 + .33 * (income - 191650),
416700: lambda income: 120910.25 + .35 * (income - 416700),
418400: lambda income: 121505.25 + .396 * (income - 418400)
}
def taxes(income):
for threshold in sorted(TAX_DICT)[::-1]:
if income >= threshold:
return TAX_DICT[threshold](income)
You could also create a regular function for each threshold instead of a lambda function.

Dictionaries work by taking all the possible hashcodes that values could have and dividing them up into buckets. When you want to look something up they hash it, check in the appropriate bucket, and see if there's something there.
This approach isn't going to work here, because if you look up a number like 100,000 the dictionary won't know to look under the hash value of 91,900 in particular.
What you want instead for this class of problem is a sorted collection of tuples that you can perform a binary search on. If the list is going to change at runtime this should be some kind of self-balancing binary tree; if not, it can just be a pre-sorted array.
In your case since there are only a few items, doing a binary search is probably more trouble than it's worth; just walking through the list should be fine.

Related

Calculate change from paid amount

Why is this code creating an infinite loop? I would think this should be an appropriate solution for this type of problem. For example, if the price was $5 and you paid $5.47, the program would print:
Quarters: 1
Dimes: 2
Nickels: 0
Pennies: 2
However, an infinite loop occurs and I'm not sure why. Anyone know the reason?
price = round(float(input("Enter the price: ")), 2)
print price
paid = round(float(input("Enter the amount paid: ")), 2)
print paid
change = round(float(paid - price), 2)
print change
quarters = 0
dimes = 0
nickels = 0
pennies = 0
while change > 0.00:
print change
if change >= .25:
change = change - .25
quarters += 1
continue
elif change >= .1:
change = change - .1
dimes += 1
continue
elif change >= .05:
change = change - .05
nickels += 1
elif change >= .01:
change = change - .01
pennies += 1
print "Quarters: " + str(quarters)
print "Dimes: " + str(dimes)
print "Nickels: " + str(nickels)
print "Pennies: " + str(pennies)
Rather than dealing with loops, I would suggest just subtracing off the change that you already gathered, prioritizing larger coins.
price = float(input("Enter the price: "))
paid = float(input("Enter the amount paid: "))
change = paid - price
if change < 0:
raise ValueError('Not enough paid')
quarters = change // 0.25
dimes = (change - (0.25 * quarters)) // 0.10
nickels = (change - (0.25 * quarters) - (0.10 * dimes)) // 0.05
pennies = 100 * (change - (0.25 * quarters) - (0.10 * dimes) - (0.05 * nickels))
print("Quarters: {:.0f}".format(quarters))
print("Dimes: {:.0f}".format(dimes))
print("Nickels: {:.0f}".format(nickels))
print("Pennies: {:.0f}".format(pennies))
There's one minor bug in the code which causes the program to only work correctly if price and amount paid are interchanged (e.g. price = 2, paid = 1). But that is not the issue causing the infinite loop.
Your code creates an infinite loop for e.g. the following arguments:
price: 5.6
paid: 5.4
The reason for the infinite loop can be seen from your own print output:
0.009999999999999275
0.009999999999999275
0.009999999999999275
0.009999999999999275
0.009999999999999275
0.009999999999999275
0.009999999999999275
...
Since change < 0.01, no if clause applies and thus the loop is never left.
How could you solve the problem more robustly?
Here's a sketch
from math import floor
change = paid - price
quarters = int(floor(change / 0.25))
change -= quarters * 0.25
dimes = int(floor(change / 0.1))
change -= dimes * 0.1
nickels = int(floor(change / 0.05))
change -= nickels * 0.05
pennies = int(floor(change / 0.01))
change -= pennies * 0.01
remaining = change
print("Quarters:", quarters)
print("Dimes:", dimes)
print("Nickels:", nickels)
print("Pennies:", pennies)
Personally I would also condense this into a loop over the coin type:
increments = {"quarter":0.25, "dimes": 0.1, "nickels": 0.05, "pennies": 0.01}
change_parts = {}
for inc_name, inc in increments.items():
amount = int(floor(change / inc))
print(inc_name, inc, amount)
change -= amount * inc
change_parts[inc_name] = amount
for inc_name, amount in change_parts.items():
print(inc_name + ":", amount)

Why is string not recognizing my output as an integer

balance = int(100)
balance *= 0.05 + balance
balance *= 0.05 + balance
balance *= 0.05 + balance
print (int(round ( balance, '.2f' )))
im trying to calculate what 100$ interest would be after 3 years compound interest.
I originally tried this
balance = 100
balance *= 0.05 + balance
balance *= 0.05 + balance
balance *= 0.05 + balance
print (format( balance, '.2f' ))
but my formatting caused the answer to be in the trillions instead of a 5 digit float.
You're multiplying the balances. Try this:
balance = int(100)
balance = balance * 0.05 + balance
balance = balance * 0.05 + balance
balance = balance * 0.05 + balance
print("{:.02f}".format(balance))
You have your operator precedence incorrect: the assignment operator is last. Thus, what you've done is
balance = balance * (0.05 + balance)
Instead, try one of the canonical ways to express interest:
rate = 0.05
balance += balance * rate
or
balance *= (1 + rate)
The parentheses aren't needed, but will help you read this.
Also, you might make a parameter (variable) for your repetition:
limit = 3
for year in range(limit):
balance *= 1 + rate
print("{:.02f}".format(balance))
You should pay attention to order of operations. balance *= 0.05 + balance will add 0.05 and balance before multiplying it to balance. What you'd want is balance = balance + balance * 0.05 or balance = balance * 1.05.
You can create a function to calculate compound interest to make it easier:
def comp_int(balance, rate, years):
return balance * (1 + rate)**years
balance = 100
rate = 0.05
years = 3
new_bal = comp_int(balance, rate, years)
print(f'{new_bal:.2f}')

An unexpected augmented assignment discount += item.total() * .1

I am following "Fluent Python" to learn Function and Design Pattern:
In chapter 6 example-code/strategy.py
def bulk_item_promo(order):
"""10% discount for each LineItem with 20 or more units"""
discount = 0
for item in order.cart:
if item.quantity >= 20:
discount += item.total() * .1 #augmented += ?
return discount
I am very confused about:
discount += item.total() * .1
I assume it overhead complicated, because it's just
discount = item.total() * .1
However, the author prefer to state it like
discount = 0*1 + 0*2 + 0*3 + item.total() * .1
to increase it complexity artificially.
What's the key points I missed? could you please provide any hints?
The code discount += item.total() * .1 is equivalent to:
discount = discount + (item.total() * 0.1)
I've added the parentheses for clarity, but they are not necessary as multiplication has precedence over addition.
Your function calculates an absolute discount by aggregating discounts for all items with quantity greater than 20. The discount equates to 10% of the undiscounted cost of in-scope items.
The same function can also be written with sum and a generator expression:
def bulk_item_promo(order):
"""10% discount for each LineItem with 20 or more units"""
return sum(item.total() * 0.1 for item in order.cart if item.quantity >= 20)
Suppose there are 3 items in the order. Call them a, b, and c. Say that each one had more than 20 units. Say that a.total() == b.total() == c.total() == 100. In the case of:
discount = item.total() * .1
discount will be 10. So you would get 10 off the entire 300. But that isn't really what you want, you want 10 off of each a.total(), b.total() and c.total(), so you want 30. This why you use += instead as it aggregates over each (qualified) item.
Every item in the basket can have a discount. To calculate the total discount, you need to add up the individual discounts for all items that have an discount, and that is what the code does. Calling the variable "total_discount" instead of "discount" might have been better.
left += right
means: Calculate the value "right", then add it to the variable left. discount_total += (formula for item discount) means calculate the item discount according to the formula, and add it to the discount_total. In your case
discount_total += item.total() * 0.1
means: Calculate the discount for this item by calculating its total and multiplying by 0.1 (which is the same as taking ten percent). Then add the discount for this item to the discount total.

TypeError: can't multiply sequence by non-int of type 'float', I can't figure out

This is that piece of code I wrote:
#This is the first ever piece of code I/'m Writing here
#This calculates the value after applying GST
#Example: here we are applying on a smartphone costing 10000
Cost = input('Enter the MRP of device here ')
Tax = 0.12
Discount = 0.05
Cost = Cost + Cost * float(Tax)
Total = Cost + Cost * float(Discount)
print(Total)
Whenever I try to execute the code it gives an exception after input:
TypeError: can't multiply sequence by non-int of type 'float'
There's a few weird parts here I'll try to break them down. The first is the one you are actually asking about which is caused by input returning a string, so you are effectively doing something like this. I'm going to lowercase the variable names to match python style
cost = "2.50"
tax = 0.12
#...
cost * tax # multiplying str and float
Fix this by wrapping the call to input with a call to float to convert the str
cost = float(input('Enter the MRP of device here '))
tax = 0.12
discount = 0.5
next you have these extra calls float(tax) and float(discount). Since both of these are floats already, you don't need this.
There is also a shorthand syntax for x = x + y which is x += y with these two things in mind, you can adjust your calculation lines:
cost += cost * tax
cost += cost * discount
print(cost)
raw input is as string,cast it into float
Cost = input('Enter the MRP of device here ')
Cost=float(Cost)
Tax = 0.12
Discount = 0.05
Cost = Cost + Cost * float(Tax)
Total = Cost + Cost * float(Discount)
print(Total)

Can anyone please explain this following programming questioƱ?

Question: Define a Python function named calculate_tax() which accepts one parameter, income, and returns the income tax. Income is taxed according to the following rule: the first $250,000 is taxed at 40% and any remaining income is taxed at 80%. For example, calculate_tax(100000) should return $100,000 * 0.40 = $40,000, while calculate_tax(300000) should return $250,000 * 0.40 + 50,000 * 0.80 = $140,000.
My question is simple, does the question ask for me to print out the whole math operation $100,000 * 0.40 = $40,000, or just the final answer$40,000?
It does say "should return $250,000 * 0.40 + 50,000 * 0.80 = $140,000," but all your function should actually return is the final value of 250000. The function should simply do the calculation and return the result. The equation is written out in order to help you create the function, not as an output requirement.
However, the best person to clarify assignments is the teacher who assigned them.
Is not it? like this:
def calculate_tax(income=250000):
tax = 0
if income <= 250000:
tax = income * 0.4
else:
tax = 250000 * 0.4 + (income - 250000) * 0.8
return int(tax)
print calculate_tax(100000) # 40000
print calculate_tax(300000) # 140000

Categories

Resources