why does my code return wrong ticket prices? I am supposed to add a time factor as well, but can't get even this to work. This is what I am supposed to do:
"""
Price of one bus ticket
time 6-17, price 2.7, age 16-64
time 18-22, price 3.5, age 16-64
time 23 and 0-5, price 4, age 16-64
for ages 0-2 ticket is free at all times
time 6-17, price 1.7, ages 3-15 and 65 -->
time 18-22, price 2.5, ages 3-15 and 65 -->
time 23 and 0-5, price 3.0, ages 3-15 and 65 -->
"""
def calculate_ticket_price(age):
ticket_price = 0
while True:
if age >= 0 or age <= 2:
ticket_price = 1.0
if age <= 15 or age >= 3 or age >= 65:
ticket_price = 1.5
if age > 15 or age < 65:
ticket_price = 2.7
return float(ticket_price)
def main():
age = 5
price = calculate_ticket_price(age)
print(price)
if __name__ == '__main__':
main()
I think it’ll return the wrong price cause you’re using or where you need an and.
Your first if statement should be:
if ((age >= 0) and (age <= 2)):
Your second if statement should be:
if (((age <= 15) and (age >= 3)) or (age >= 65)):
Then your third one:
if ((age > 15) and (age < 65)):
def calculate_ticket_price(age, time):
while True:
if time >= 6 or time <= 17 and age > 15 or age < 65:
ticket_price = 2.7
elif time >= 18 or time <= 22 and age > 15 or age < 65:
ticket_price = 3.5
elif time >= 23 or time >= 0 or time <= 5 and age > 15 or age < 65:
ticket_price = 4.0
elif time >= 6 or time <= 17 and age <= 15 or age >= 3 or age >= 65:
ticket_price = 1.7
elif time >= 18 or time <= 22 and age <= 15 or age >= 3 or age >= 65:
ticket_price = 2.5
elif time >= 23 or time >= 0 or time <= 5 and age <= 15 or age >= 3 or age >= 65:
ticket_price = 3.0
else:
ticket_price = 0.0
return float(ticket_price)
def main():
age = 5
time = 12
price = calculate_ticket_price(age, time)
print(price)
if __name__ == '__main__':
main()
Made these edits. Should there be and between every >=, <= etc..?
You're using or when I think you want to be using and. For example, this condition:
if age >= 0 or age <= 2:
is going to be true for any positive number, since the first part will always match.
You also want to be using elif so that only one of these blocks will happen. Your last condition:
if age > 15 or age < 65:
ticket_price = 2.7
is going to happen any time the age is under 65 or over 15 (which is going to be every number), so I'd expect that your function just always returns 2.7.
A simpler way to write this function that follows the simple age-only rules you're trying to implement would be:
def calculate_ticket_price(age: int) -> float:
if age <= 2:
return 0.0 # infant price
elif age <= 15:
return 1.5 # youth price
elif age <= 65:
return 2.7 # adult price
else:
return 1.5 # senior price
In this very simple example, only the first condition that matches will return a value, so testing both sides of the range isn't necessary.
You can also check for an age to be within a particular range by writing an expression like 2 < age <= 15, or age > 2 and age < 15, or even age in range(2, 16).
Note that putting everything inside a while loop serves no purpose at all -- avoid having lines of code that don't do anything useful, since they're just one more place for bugs to appear. :)
As far as having the function account for both age and time, I notice that the fare table amounts to giving youth/seniors the same $1 discount regardless of what time it is, so I might simplify it down like this rather than have a different condition for each age/time combination:
def calculate_ticket_price(time: int, age: int) -> float:
# Infants ride free
if age <= 2:
return 0.0
# Youth and seniors get a $1.00 discount
discount = 1.0 if age <= 15 or age >= 65 else 0.0
if 6 <= time <= 17:
return 2.7 - discount
if 18 <= time <= 22:
return 3.5 - discount
if 0 <= time <= 5 or time == 23:
return 4.0 - discount
raise ValueError(f"invalid time {time}!")
Related
I have three 2D arrays SandArray,ClayArray, and SiltArray. I also have a function described here. Below is my code, when I run the script I get a ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
def TextureClass(sand, clay, silt):
#if sand + clay > 100 or sand < 0 or clay < 0:
# raise Exception('Inputs adds over 100% or are negative')
if silt + 1.5*clay < 15:
textural_class = 'sand'
elif silt + 1.5*clay >= 15 and silt + 2*clay < 30:
textural_class = 'loamy sand'
elif (clay >= 7 and clay < 20 and sand > 52 and silt + 2*clay >= 30) or (clay < 7 and silt < 50 and silt + 2*clay >= 30):
textural_class = 'sandy loam'
elif clay >= 7 and clay < 27 and silt >= 28 and silt < 50 and sand <= 52:
textural_class = 'loam'
elif (silt >= 50 and clay >= 12 and clay < 27) or (silt >= 50 and silt < 80 and clay < 12):
textural_class = 'silt loam'
elif silt >= 80 and clay < 12:
textural_class = 'silt'
elif clay >= 20 and clay < 35 and silt < 28 and sand > 45:
textural_class = 'sandy clay loam'
elif clay >= 27 and clay < 40 and sand > 20 and sand <= 45:
textural_class = 'clay loam'
elif clay >= 27 and clay < 40 and sand <= 20:
textural_class = 'silty clay loam'
elif clay >= 35 and sand > 45:
textural_class = 'sandy clay'
elif clay >= 40 and silt >= 40:
textural_class = 'silty clay'
elif clay >= 40 and sand <= 45 and silt < 40:
textural_class = 'clay'
else:
textural_class = 'na'
return textural_class
Texture = TextureClass(SandArray,ClayArray,SiltArray)
Texture should be an array with the same shape as SandArray, ClayArray, and SiltArray but with the textural_class str as its values.
Is it possible to have an output array of text from a function having conditions and using arrays as its input arguments and if so, what am I missing?
Edit:
Having tried texture = np.array(list(map(TextureClass,SandArray,ClayArray,SiltArray))) I still get the same ValueError
I'm not really that knowledgeable in numpy, but, from what I searched in other questions, you could use vectorize to wrap your function.
Here's an example: How to apply a function / map values of each element in a 2d numpy array/matrix?
Using my previous approach of mostly built-in python-code:
You could zip the three arrays (either inside or outside your function, but I'd do it outside), then loop over the zipped arrays.
The zip() function returns a zip object, which is an iterator of tuples where the first item in each passed iterator is paired together, and then the second item in each passed iterator are paired together etc.
If the passed iterators have different lengths, the iterator with the least items decides the length of the new iterator.
Emphasis on the fact that it's assumed the three arrays have the same length. And, in this case, you'd need to bi-dimensionally zip:
So, instead of Texture = TextureClass(SandArray,ClayArray,SiltArray), you could use:
soilCompositions = (zip(sands, clays, silts) for sands, clays, silts in zip(SandArray, ClayArray, SiltArray))
Textures = ((TextureClass(sand, clay, silt) for sand, clay, silt in soilCompositionRow) for soilCompositionRow in soilCompositions)
Notice that I used generator comprehension, but you could just as easy use list comprehension instead:
soilCompositions = (zip(sands, clays, silts) for sands, clays, silts in zip(SandArray, ClayArray, SiltArray))
Textures = [[TextureClass(sand, clay, silt) for sand, clay, silt in soilCompositionRow] for soilCompositionRow in soilCompositions]
Applying a function to each element of a matrix requires np.vectorize. The documentation is available here. An example of a similar questions can be found here:How to apply a function / map values of each element in a 2d numpy array/matrix?.
I think this question is unique in that it shows the range of functions that np.vectorize works on. My original issue was whether or not np.vectorize would work for a conditional function like the one in my question.
def TextureClass(sand, clay, silt):
#if sand + clay > 100 or sand < 0 or clay < 0:
# raise Exception('Inputs adds over 100% or are negative')
if silt + 1.5*clay < 15:
textural_class = 'sand'
elif silt + 1.5*clay >= 15 and silt + 2*clay < 30:
textural_class = 'loamy sand'
elif (clay >= 7 and clay < 20 and sand > 52 and silt + 2*clay >= 30) or (clay < 7 and silt < 50 and silt + 2*clay >= 30):
textural_class = 'sandy loam'
elif clay >= 7 and clay < 27 and silt >= 28 and silt < 50 and sand <= 52:
textural_class = 'loam'
elif (silt >= 50 and clay >= 12 and clay < 27) or (silt >= 50 and silt < 80 and clay < 12):
textural_class = 'silt loam'
elif silt >= 80 and clay < 12:
textural_class = 'silt'
elif clay >= 20 and clay < 35 and silt < 28 and sand > 45:
textural_class = 'sandy clay loam'
elif clay >= 27 and clay < 40 and sand > 20 and sand <= 45:
textural_class = 'clay loam'
elif clay >= 27 and clay < 40 and sand <= 20:
textural_class = 'silty clay loam'
elif clay >= 35 and sand > 45:
textural_class = 'sandy clay'
elif clay >= 40 and silt >= 40:
textural_class = 'silty clay'
elif clay >= 40 and sand <= 45 and silt < 40:
textural_class = 'clay'
else:
textural_class = 'na'
return textural_class
vector_func = np.vectorize(TextureClass)
textures = vector_func(SandArray, ClayArray, SiltArray)
Using the example dataframe below,
How do I iterate over both Grade 1 and Grade 2 columns to select any grade 1 greater than 24 with any Grade 2 greater than 50 using list_comprehension or vectorization mentioned here
import pandas as pd
data = {'Name':['Jai', 'Princi', 'Gaurav', 'Anuj'],
'Grade 1':[27, 24, 22, 32],
'Grade 2':[60, 50, 75, 60],
'Final Grade':[77, 74, 97, 92]}
df = pd.DataFrame(data)
print(df[['Name', 'Grade 1', 'Grade 2','Final Grade']])
Based on those conditions I would like the expected output to return something like:
Jai has Grade 1 score of 27 and Grade 2 score of 60
Anuj has Grade 1 score of 32 and Grade 2 score 60
Gaurav has Grade 1 score of 22 and Grade 2 score of 75
Following a tutorial but trying to go beyond in understanding how to implement either of those concepts.
Your question isn't really clear so I hope you can clarify things a bit. For example, you need Grade 1 which are greater than 24 but in your expected output, you are expecting Gaurav with 22.
However, to make things simpler, I would say never try to iterate in pandas. At the very least, it is a practice that is best left for exception cases.
Here you can use conditional assignments :
df[(df['Grade 1'] > 24) & (df['Grade 2'] > 50 )]]
out :
Name Grade 1 Grade 2 Final Grade
Jai 27 60 77
Anuj 32 60 92
Edit : If in case you wish to have an output with either Grade 1 > 24 OR Grade 2 > 50, just replace & with '|'
Do you mean something like this?
res = df[(df['Grade 1'] > 24) & (df['Grade 2'] > 50)]
print(res)
Name Grade 1 Grade 2 Final Grade
0 Jai 27 60 77
3 Anuj 32 60 92
You can use apply, although, in this case, I do not think it will make too much difference.
df[(df["Grade 1"] > 24) & (df["Grade 2"] > 50)].apply(
lambda x: f"{x['Name']} has Grade 1 score of {x['Grade 1']} and Grade 2 score of {x['Grade 2']}",
axis=1,
).tolist()
['Jai has Grade 1 score of 27 and Grade 2 score of 60',
'Anuj has Grade 1 score of 32 and Grade 2 score of 60']
I'm trying to sum integer values from the list using sum function. Unfortunately, it is adding all the values of the list but not those which I need from the user.
Here is my code:
tourist_attractions = []
distance = []
entry_cost = []
for i in range(3):
tourist_attractions.append (input("Enter Tourist place: "))
tourist_distance =(int(input("Enter distance: ")))
if tourist_distance > 50:
print("Invalid Entry")
continue
if tourist_distance <= 50:
distance.append(tourist_distance)
cost = (float(input("Enter cost: ")))
if cost > 100:
print("cost must be between 1-100")
continue
if cost > 0 or cost <= 100:
entry_cost.append(cost)
print()
for line in tourist_attractions:
print("Place:", line)
for line in distance:
print("Distance:", line)
for line in entry_cost:
print("Cost:", line)
print()
number_of_places_to_visit = int(input("Total number of places to visit: "))
x = 1
while x <= number_of_places_to_visit:
select_tourist_place = input("select tourist place, 0-3: ")
x = x + 1
if select_tourist_place == "0":
print(tourist_attractions[0], distance[0], entry_cost[0])
elif select_tourist_place == "1":
print(tourist_attractions[1], distance[1], entry_cost[1])
elif select_tourist_place == "2":
print(tourist_attractions[2], distance[2], entry_cost[2])
elif select_tourist_place == "3":
print(tourist_attractions[3], distance[3], entry_cost[3])
elif select_tourist_place == "4":
print(tourist_attractions[4], distance[4], entry_cost[4])
print("total cost: " , sum(entry_cost))
Result I am getting:
Enter Tourist place: London
Enter distance: 25
Enter cost: 15
Enter Tourist place: Manchester
Enter distance: 30
Enter cost: 15
Enter Tourist place: Scotland
Enter distance: 50
Enter cost: 20
Place: London
Place: Manchester
Place: Scotland
Distance: 25
Distance: 30
Distance: 50
Cost: 15.0
Cost: 15.0
Cost: 20.0
Total number of places to visit: 2
select tourist place, 0-3: 0
London 25 15.0
select tourist place, 0-5: 1
Manchester 30 15.0
total cost: 50.0
>>>
I can understand, at the moment it is summing up all the appended list of entry_cost and giving me the total of 50 which should be 15 from London and 15 from Manchester. Any help?
print("total cost: " , sum(entry_cost))
definitely states your are iterating over ALL entry costs. You would want to store the selected indices and sum over the entries of those indices.
Here is my dataframe , I need to create a new column based on the timehour which the row value be like (morning, afternoon, evening, night)
Here is my code
if ((prods['hour'] < 4) & (prods['hour'] > 8 )):
prods['session'] = 'Early Morning'
elif ((prods['hour'] < 8) & (prods['hour'] > 12 )):
prods['session'] = 'Morning'
elif ((prods['hour'] < 12) & (prods['hour'] > 16 )):
prods['session'] = 'Noon'
elif ((prods['hour'] < 16) & (prods['hour'] > 20 )):
prods['session'] = 'Eve'
elif ((prods['hour'] < 20) & (prods['hour'] > 24 )):
prods['session'] = 'Night'
elif ((prods['hour'] < 24) & (prods['hour'] > 4 )):
prods['session'] = 'Late Night'
Here is the error i got
ValueError Traceback (most recent call
last) in
----> 1 if (prods['hour'] > 4 and prods['hour']< 8):
2 prods['session'] = 'Early Morning'
3 elif (prods['hour'] > 8 and prods['hour'] < 12):
4 prods['session'] = 'Morning'
5 elif (prods['hour'] > 12 and prods['hour'] < 16):
/anaconda3/lib/python3.7/site-packages/pandas/core/generic.py in
nonzero(self) 1476 raise ValueError("The truth value of a {0} is ambiguous. " 1477 "Use a.empty,
a.bool(), a.item(), a.any() or a.all()."
-> 1478 .format(self.class.name)) 1479 1480 bool = nonzero
ValueError: The truth value of a Series is ambiguous. Use a.empty,
a.bool(), a.item(), a.any() or a.all().
Kindly help
Use cut or custom function with and and also changed < to > and > to <= and also for each value add return:
prods = pd.DataFrame({'hour':range(1, 25)})
b = [0,4,8,12,16,20,24]
l = ['Late Night', 'Early Morning','Morning','Noon','Eve','Night']
prods['session'] = pd.cut(prods['hour'], bins=b, labels=l, include_lowest=True)
def f(x):
if (x > 4) and (x <= 8):
return 'Early Morning'
elif (x > 8) and (x <= 12 ):
return 'Morning'
elif (x > 12) and (x <= 16):
return'Noon'
elif (x > 16) and (x <= 20) :
return 'Eve'
elif (x > 20) and (x <= 24):
return'Night'
elif (x <= 4):
return'Late Night'
prods['session1'] = prods['hour'].apply(f)
print (prods)
hour session session1
0 1 Late Night Late Night
1 2 Late Night Late Night
2 3 Late Night Late Night
3 4 Late Night Late Night
4 5 Early Morning Early Morning
5 6 Early Morning Early Morning
6 7 Early Morning Early Morning
7 8 Early Morning Early Morning
8 9 Morning Morning
9 10 Morning Morning
10 11 Morning Morning
11 12 Morning Morning
12 13 Noon Noon
13 14 Noon Noon
14 15 Noon Noon
15 16 Noon Noon
16 17 Eve Eve
17 18 Eve Eve
18 19 Eve Eve
19 20 Eve Eve
20 21 Night Night
21 22 Night Night
22 23 Night Night
23 24 Night Night
After some research, this is the simplest and most efficient implementation I could find.
prods['period'] = (prods['hour_int'].dt.hour % 24 + 4) // 4
prods['period'].replace({1: 'Late Night',
2: 'Early Morning',
3: 'Morning',
4: 'Noon',
5: 'Evening',
6: 'Night'}, inplace=True)
I hope this helps.
Some of the vars are in Portuguese sorry. I am trying to show how much of which type of money bills you will and will not get on a atm:
example:
IN: $123,45
OUT:1 OF $100 BILL, 0 OF $50 BILL, 1 OF $20 BILL, 0 OF $10 BILL and etc.
This is what I did so far but I can't do the bill that will not come on the atm.
r = 0
print('='*20)
print('{:^20}'.format('CAIXA ELETRÔNICO'))
print('{:^20}'.format(' Banco do Romeu '))
print('='*20)
caixa = float(input('Qual será o valor sacado? '))
total = caixa
ced = 100
totalced = 0
while True:
if total >= ced:
total = total - ced
totalced += 1
else:
if totalced > 0:
print(f'{totalced} notas(s) de R${ced}')
elif ced == 100:
ced = 50
elif ced == 50:
ced = 20
elif ced == 20:
ced = 10
elif ced == 10:
ced = 5
elif ced == 5:
ced = 2
elif ced == 2:
ced = 1
elif ced == 1:
ced = 0.50
elif ced == 0.50:
ced = 0.25
elif ced == 0.25:
ced = 0.10
elif ced == 0.10:
ced = 0.05
elif ced == 0.05:
ced = 0.01
totalced = 0
if total == 0:
break
You can do a greedy approach and try to subtract the highest value bill and keep a count of how many times you subtracted from each bill. For example:
423,45
You start with $100, you can subtract it 4 times. You're left with 23,45.
Then you go on to $50. You can't subtract $50 from 23,45 so you go to the next highest bill, $20.
You can subtract one $20 from 23,45 and you're left with ,45.
You keep on going and keep count until you can't subtract anymore. Then you print out the count of subtractions from each bill. Hope that makes sense!
You can subtract value from initial value.
variable valor is the initial value
valor = 162
cells = []
money = [100, 50, 20, 10, 5, 2]
for _ in money:
while True:
if valor >= _:
if valor - _ < money[-1] or (valor % _) % money[-1] != 0:
if valor == _:
cells.append(_)
break
valor -= _
cells.append(_)
else:
break
print(cells)
>>> [100, 50, 10, 2]