HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Calculate shipping cost

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
costcalculateshipping

Problem

Could I code differently to slim down the point of this Python source code? The point of the program is to get the user's total amount and add it to the shipping cost. The shipping cost is determined by both country (Canada or USA) and price of product: The shipping of a product that is $125.00 in Canada is $12.00.

input ('Please press "Enter" to begin')

while True: print('This will calculate shipping cost and your grand total.')

totalAmount = int(float(input('Enter your total amount: ').replace(',', '').replace(', '')))
Country = str(input('Type "Canada" for Canada and "USA" for USA: '))

usa = "USA"
canada = "Canada"
lessFifty = totalAmount = 50.01 and totalAmount = 100.01 and totalAmount <= 150
twoHundred = totalAmount

if Country == "USA":
    if lessFifty:
        print('Your shipping is: $6.00')
        print('Your grand total is: ,totalAmount + 6)
    elif fiftyHundred:
        print('Your shipping is: $8.00')
        print('Your grand total is: ,totalAmount + 8)
    elif hundredFifty:
        print('Your shipping is: $10.00')
        print('Your grand total is: ,totalAmount + 10)
    elif twoHundred:
        print('Your shipping is free!')
        print('Your grand total is: ,totalAmount)

if Country == "Canada":
    if lessFifty:
        print('Your shipping is: $8.00')
        print('Your grand total is: ,totalAmount + 8)
    elif fiftyHundred:
        print('Your shipping is: $10.00')
        print('Your grand total is: ,totalAmount + 10)
    elif hundredFifty:
        print('Your shipping is: $12.00')
        print('Your grand total is: ,totalAmount + 12)
    elif twoHundred:
        print('Your shipping is free!')
        print('Your grand total is: ,totalAmount)

endProgram = input ('Do you want to restart the program?')
if endProgram in ('no', 'No', 'NO', 'false', 'False', 'FALSE'):
    break

Solution

I would not hard-code the fee logic, but instead store it as pure data. It's easier to maintain, even allowing to load it from a file.
Then, it boils down to a range-based lookup, which is quite classical (cf HLOOKUP in spreadsheet software, with so called "approximate search").

In Python, we can perform such a search via bisect, relying on lexicographic order (and infinity as an unreachable upper bound).

Separated core logic would look like :

from bisect import bisect

#For each country, list of (x,y) = (cost_threshold, fee)
#For first x such cost <= x, pick y for fee.
inf = float("inf")
shippingFees = { 'USA' :    [ (50, 6), (100, 8),  (150, 10), (inf, 0) ],
                 'CANADA' : [ (50, 8), (100, 10), (150, 12), (inf, 0) ]
               }
#Make sure it is sorted (required for lookup via bisect)
#FIXME : Actually it would be better to assert it is already sorted,
#        since an unsorted input might reveal a typo.
for fee in shippingFees.values() : fee.sort()

def getShippingFee(amount, country):
   fees = shippingFees[country.upper()] #raise KeyError if not found.
   idx = bisect(fees, (amount,) )
   return fees[idx][1]


Update

Here is a sample of "working application" using the helper function, assuming you have saved the code snippet above as prices.py (which should be stored in a module, but that's another story).

NB : I have dropped the exit part, since I don't like to type no when I can hit CTRL+C.

#!/usr/bin/python2
""" Your description here """

from prices import getShippingFee

print('This will calculate shipping cost and your grand total.')

while True:

   #TODO : proper input processing, python3 compatible.
   totalAmount = float(raw_input('Enter your total amount: ').replace(',', '').replace(', ''))
   country = raw_input('Type "Canada" for Canada and "USA" for USA: ').strip().upper()

   try :  #TODO : proper country check.
      shippingFee = getShippingFee(totalAmount, country)
      grandTotal = totalAmount + shippingFee
      if shippingFee :
         print('Your shipping cost is: %.2f' % shippingFee)
      else :
         print('Your shipping is free!')
      print('Your grand total is: %.2f' % grandTotal)

   except KeyError :
      print ("Sorry, we don't ship to this hostile country : %s" % country)

Code Snippets

from bisect import bisect

#For each country, list of (x,y) = (cost_threshold, fee)
#For first x such cost <= x, pick y for fee.
inf = float("inf")
shippingFees = { 'USA' :    [ (50, 6), (100, 8),  (150, 10), (inf, 0) ],
                 'CANADA' : [ (50, 8), (100, 10), (150, 12), (inf, 0) ]
               }
#Make sure it is sorted (required for lookup via bisect)
#FIXME : Actually it would be better to assert it is already sorted,
#        since an unsorted input might reveal a typo.
for fee in shippingFees.values() : fee.sort()

def getShippingFee(amount, country):
   fees = shippingFees[country.upper()] #raise KeyError if not found.
   idx = bisect(fees, (amount,) )
   return fees[idx][1]
#!/usr/bin/python2
""" Your description here """

from prices import getShippingFee

print('This will calculate shipping cost and your grand total.')

while True:

   #TODO : proper input processing, python3 compatible.
   totalAmount = float(raw_input('Enter your total amount: ').replace(',', '').replace('$', ''))
   country = raw_input('Type "Canada" for Canada and "USA" for USA: ').strip().upper()

   try :  #TODO : proper country check.
      shippingFee = getShippingFee(totalAmount, country)
      grandTotal = totalAmount + shippingFee
      if shippingFee :
         print('Your shipping cost is: %.2f' % shippingFee)
      else :
         print('Your shipping is free!')
      print('Your grand total is: %.2f' % grandTotal)

   except KeyError :
      print ("Sorry, we don't ship to this hostile country : %s" % country)

Context

StackExchange Code Review Q#21113, answer score: 10

Revisions (0)

No revisions yet.