Alternative solution to Sal's Shipping project!

def ground_shipping(weight):

if weight <= 2.0:
price_per_pound = 1.50
elif weight <= 6:
price_per_pound = 3.00
elif weight <= 10:
price_per_pound = 4.00
else:
price_per_pound = 4.75

return 20+(weight*price_per_pound)

premium_ground_shipping = 125.00

def drone_shipping(weight):

if weight <= 2.0:
price_per_pound = 4.50
elif weight <= 6:
price_per_pound = 9.00
elif weight <= 10:
price_per_pound = 12.00
else:
price_per_pound = 14.25

return (weight*price_per_pound)

print(ground_shipping(8.4))
print(drone_shipping(1.5))

def cheapest_shipping(weight):
ground = ground_shipping(weight)
drone = drone_shipping(weight)
premium = premium_ground_shipping
if ground < drone and ground < premium:
return "Use the Ground Shipping method, it costs " + str(ground) elif drone < ground and drone < premium: return "Use the Drone Shipping method, it costs " + str(drone)
else:
return “Use the Premium Shipping method, it costs $” + str(premium)

print(cheapest_shipping(4.8))
print(cheapest_shipping(41.5))

Please
(1) Post a link to the project mentioned

(2) Post readable code that is recognizable as Python (and that can be cut-and-pasted for testing) by using the </> icon that is near the middle of the menu bar that appears at the top of the text box when you begin typing.

(3) Let us know what you feel is different or unique about your approach.

1 Like

Hi natasha0405,
I was curious to see how others were approaching this project. Looks like we did something similar except I combined the two functions ground_shipping(weight) and drone_shipping(weight) because I noticed they had the same weight tiers. My new combined function takes two parameters weight and shipping_type. I’d like to hear people’s suggestions on if my approach would be considered more efficient or if it would make the code less clear.

Here is the project link:
https://www.codecademy.com/paths/computer-science/tracks/cspath-flow-data-iteration/modules/dspath-control-flow/projects/sals-shipping

premium_ground_shipping = 125
def cost_shipping(weight,shipping_type):
if weight<=2:
  ground_price_per_pound = 1.5
  drone_price_per_pound = 4.5
if weight>2 and weight<=6:
  ground_price_per_pound = 3
  drone_price_per_pound = 9
if weight>6 and weight<=10:
  ground_price_per_pound = 4
  drone_price_per_pound = 12
if weight>10:
  ground_price_per_pound = 4.75
  drone_price_per_pound = 14.24
if shipping_type.lower()=="ground":
  cost = (weight*ground_price_per_pound) + 20
if shipping_type.lower()=="drone":
  cost = weight*drone_price_per_pound
return cost


def cheapest_shipping_method(weight):
cheapest_shipping = 0
cheapest_shipping_string = ""
ground_price = cost_shipping(weight,"ground")
drone_price = cost_shipping(weight,"drone")
if ground_price<drone_price and ground_price<premium_ground_shipping:
  cheapest_shipping = ground_price
  cheapest_shipping_string = "ground"
if drone_price<ground_price and drone_price<premium_ground_shipping:
  cheapest_shipping = drone_price
  cheapest_shipping_string = "drone"
if premium_ground_shipping<ground_price and premium_ground_shipping<drone_price:
  cheapest_shipping = premium_ground_shipping
  cheapest_shipping_string = "premium ground shipping"
return "The chapest shipping method is " + cheapest_shipping_string + " and costs " + str(cheapest_shipping) + "."

print(cheapest_shipping_method(4.8))
print(cheapest_shipping_method(41.5))


Hi, data9… – The first function is a nice twist. One consideration might be maintenance. For instance, if shipping prices were to change in one or the other categories, which approach would make it easier to update the prices?

Any function that involves a lengthy chain of if’s or if-elif-else can (probably) be greatly simplified if you have some more data structures (lists and -especially - dictionaries) at your disposal. Those will be coming up in forthcoming lessons. So if you are interested in code efficiency and clarity, you might want to revisit this project later.

The second function can be simplified quite a bit

cheapest = premium
if drone < cheapest:
    cheapest = drone
if ground < cheapest:
    cheapest = ground
return cheapest

There are many possible variations on the above.

Good point about ease of maintenance for the shipping prices! I will definitely revisit this problem once I learn more about lists and dictionaries.

1 Like
def get_rate_index(weight):
  return tabs.index([x for x in tabs if weight > x][-1])

def ground_shipping(weight):
  return b_rate + g_rates[get_rate_index(weight)] * weight

def drone_shipping(weight):
  return d_rates[get_rate_index(weight)] * weight

def lowest_cost(weight):
  ground = ground_shipping(weight)
  drone = drone_shipping(weight)
  return ('Premium', premium) if premium < ground \
or premium < drone else ('Ground', ground) if ground < drone \
else ('Drone', drone)

# maintenance section

premium = 125.00
b_rate = 20.00
tabs = [0, 2, 6, 10]
g_rates = [1.50, 3.00, 4.00, 4.75]
d_rates = [4.50, 9.00, 12.00, 14.25]

# compute section

print ("{:.2f}".format(ground_shipping(8.4)))
print ("{:.2f}".format(drone_shipping(1.5)))

# 53.60
# 6.75

print ("{}: {:.2f}".format(lowest_cost(4.8)[0], lowest_cost(4.8)[1]))
print ("{}: {:.2f}".format(lowest_cost(41.5)[0], lowest_cost(41.5)[1]))

# Ground: 34.40
# Premium: 125.00

We’re just throwing this out there, not suggesting a better solution. If this were written as a class we wouldn’t have dependencies on global objects, but that is for another discussion.

1 Like

C’est ça, justement!

1 Like

Took me a while to get it; but, wait. Did I get it?

Was I critiquing your comment? Sorry if it came off that way, but nothing of the sort was ever intended. It was only a when one revisits this topic sort of thing to toss in.

Or were you simply saying, “That’s right?”

1 Like

This looks much more efficient than my solution but a bit more advanced than what I know at the moment.

1 Like

I was simply saying that you nicely encapsulated my comment in code.

(But I was a bit confused, as I had inferred (incorrectly, it seems) from some earlier comments that it was frowned upon to post techniques more advanced than those that had been thus far explored: lists do not come up until the next segment of this course, nor dictionaries until two courses down the line.)

1 Like

A sneak peek can do no harm so long as the learner doesn’t attempt to use a solution they don’t understand or that the SCT is not expecting. We always encourage staying with and following the instructions. Also encouraged is review of concepts, and doubling back over earlier lessons/units to reinforce the concepts learned and meld them with newer material.

I generally stress that something is outside of the scope of the lesson. Surely in school you must have peeked ahead in the text book? I know I always did, in addition to doing the questions in C. section of lesson exercises that teachers never assigned. It was more fun that way.

However, your point is valid and one should stay your course accordingly.

1 Like

I am looking at what other versions are and I am impressed by how everyone simplify the code. However, I have a question about this part. What if both drone and ground are cheaper than premium in this case. Let’s say ground<drone<premium. It looks like it will process through the first if condition and it’s True, so it will return cheapest=drone, but actually the cheapest is ground. Am I understanding it wrong?

Hi, @fenrir913

In the case you mention, note that in the first if statement, cheapest gets re-defined down to the drone price. That’s the new price to beat. If ground is less, it is no longer compared with premium, it is compared with the new cheapest, which is drone.

Let’s ask Python about some more combinations:

def cheap(premium, ground, drone):
    
    cheapest = premium
    cheapest_string = "premium"
    
    if drone < cheapest:
        cheapest = drone
        cheapest_string = "drone"
        
    if ground < cheapest:
        cheapest = ground
        cheapest_string = "ground"
        
    return cheapest_string, cheapest

# case 1: ground < drone < premium
premium = 100
drone = 50
ground = 10
print('case 1: ground < drone < premium:', cheap(premium, ground, drone))

# case 2: drone < ground < premium
premium = 100
drone = 10
ground = 50
print('case 2: drone < ground < premium:', cheap(premium, ground, drone))
 
# case 3: premium < ground < drone
premium = 10
drone = 100
ground = 50
print('case 3: premium < ground < drone:', cheap(premium, ground, drone))

# case 4: premium < drone < ground
premium = 10
drone = 50
ground = 100
print('case 4: premium < drone < ground:', cheap(premium, ground, drone))

# case 5: ground < premium < drone
premium = 50
drone = 100
ground = 10
print('case 5: ground < premium < drone:', cheap(premium, ground, drone))

# case 6: drone< premium < ground
premium = 50
drone = 10
ground = 100
print('case 6: drone < premium < ground:', cheap(premium, ground, drone))

Output:

case 1: ground < drone < premium: ('ground', 10)
case 2: drone < ground < premium: ('drone', 10)
case 3: premium < ground < drone: ('premium', 10)
case 4: premium < drone < ground: ('premium', 10)
case 5: ground < premium < drone: ('ground', 10)
case 6: drone < premium < ground: ('drone', 10)

I think I got it. I didn’t notice that there is no return inside those ifs so the process will keep going. Thanks for the explanation and examples

1 Like

Aside

If we’re permitted to use built-in functions, min() will do the task with no conditional.

  x = premium, drone_shipping(weight), ground_shipping(weight)
  y = min(x)
  return ('Premium', 'Drone', 'Ground')[x.index(y)], y