List index out of range? If statement - python-3.x

I have a truly puzzling issue
Im using some nested if statements to produce a list, using variables from lists
if List1[0] or List2[0] or List3[0] or List4[0] or List5[0] == 'Something':
Now my assumption is that it would check for a value in either spot to be my specific word, then continue to the next statement if not, however it stops here.
here's a little bit more of the breakdown so you can see my goal here
for i in range(5):
if List1[0] or List2[0] or List3[0] List4[0] or List5[0] == 'Something':
SuperList.append('example1, example2, example3')
if List1[0] == 'Something':
List1.remove('Something')
elif List2[0] == 'Something':
List2.remove('Something')
elif List3[0] == 'Something':
List3.remove('Something')
elif List4[0] == 'Something':
List4.remove('Something')
elif List5[0] == 'Something':
List5.remove('Something')
elif List1[0] or List2[0] or List3[0] or List4[0] or List5[0] == 'SomethingElse':ECT.....
Anyway, i know for certain that all lists 1-5 contain exactly 1 Word, as i had my program print them all too me prior to the long if/nested if function to come
Any help would be greatly appreciated

I believe what the problem here is that you are only comparing List5[0] to 'Something'. You need to compare 'Something' to each value individually. (As a side note, because you are not comparing all of the values, Python expects a boolean value, while your lists hold string values).
To fix your problem you could do this for example:
if List1[0] == 'Something' or List2[0] == 'Something' or List3[0] == 'Something' or List4[0] == 'Something' or List5[0] == 'Something':
# The rest of your code here
Again, you have to compare each value individually so that they can become booleans. That seems to be the only problem with your code. I hope this cleared it up for you.

Related

How to solve Unbound Local error in my conditional block

I need to find the discount of an order
I used the following code to make the string input of order numbers to a dictionary and thenused sum() to find the total of the order
However I wish to have an offer discount if there is one-1 and one-3 and (one-4 or one-5 or one-6)
But then after the conditional block when I want to multiply it I receive an Unbound Error
def compute_cost(order):
"""
Function 2: compute_cost(order)
Parameters: order (String)
Return: Final cost of order
"""
numcount = {}
orderlist = map(int, order)
for i in orderlist:
if numcount.get(i):
numcount[i] += 1
else:
numcount[i] = 1
for i in numcount:
if i == 1:
numcount[i] = numcount[i]*4.25
elif i == 2:
numcount[i] = numcount[i]*2.50
elif i == 3:
numcount[i] = numcount[i]*2.00
elif i == 4:
numcount[i] = numcount[i]*1.25
elif i == 5:
numcount[i] = numcount[i]*1.50
elif i == 6:
numcount[i] = numcount[i]*1.75
elif i == 7:
numcount[i] = numcount[i]*3.75
else:
return print("Your order has a number outside of the range (1:7)")
order_total = sum(numcount.values())
if(numcount[1] == 1 and
numcount[3] == 1 and
(numcount[4] == 1 or
numcount[5] == 1 or
numcount[6] == 1)):
discount1 = 0.20
order_total1 = order_total*discount1
return order_total1
Please help me
Thank you for your time and effort
EDIT
If you have a better way for me to find the values and save them in a dictionary I am open to constructive criticism too
Depending on the input, the numcount-dict may or may not have all the keys.
Case 1: UnboundLocalError
When calling the function with compute_cost('12323123'), the numcount-dict becomes:
{1: 2, 2: 3, 3: 3}
The if-statement first checks if numcount[1] == 1, which evaluates to False. Therefore the whole expression is False and Python doesn't even (need to) check the rest. (This is called short-circuit evaluation.)
Because the if-statement evaluates to False, discount1 is not set at all, so you get UnboundLocalError: local variable 'discount1' referenced before assignment.
Solution:
Add an else-clause that sets discount1 to 1 (= no discount) when the condition is False:
if (numcount[1] == 1 and numcount[3] == 1 and (numcount[4] == 1 or
numcount[5] == 1 or numcount[6] == 1)):
discount1 = 0.20
else:
discount1 = 1
Case 2: KeyError
Now, when calling the function with compute_cost('32235664'), the numcount-dict becomes:
{3: 2, 2: 2, 5: 1, 6: 2, 4: 1}
The if-statement first checks if numcount[1] == 1, but that key does not exist so Python raises a KeyError. Depending on your input and how far Python needs to evaluate the if-statement, you may get that KeyError or not.
Solution:
Make sure that the numcount-dict contains all keys from the beginning. You already know how many items the dict must have because you limit your input to the range (1:7). Therefore you can initalize the dict as:
numcount = {1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0}
EDIT: is there a better way?
Sure there is, there almost always is a better way:
prices = {'1':4.25, '2':2.50, '3':2.00, '4':1.25, '5':1.50, '6':1.75, '7':3.75}
orders = '12323456'
total = sum(prices[order] for order in orders)
if (all(orders.count(type) >= 1 for type in '13') and # multiple ANDs with 'all'
any(True for type in '456' if orders.count(type) >=1)): # multiple ORs with 'any'
discount = 0.2
else:
discount = 1
print('Order value: {}\nDiscount: {}\nOffer: {:.2f}'.format(total, discount, discount * total))
You now can easily extend your prices dictionary or the conditions for a discount. I assumed that the condition for a discount is that at least one item was ordered, not exactly one. Therefore I used >=1 which you can change into ==1 if it needs to be exactly one.

Problem with my small dictionary quiz. can someone explain this error please

d = {'Red': 1, 'Green': 2, 'Blue': 3}
for color_key, value in d.items():
userinput == (input(color_key))
if userinput == (d[color_key]):
print("correct")
else:
print("wrong")
Hi everyone, i am trying to simulate a quiz with this dictionary. I want to iterate through the dictionary and prompt the user for the questions (which is the key) (i.e what is the number for the colour: color_key). I then want the user to put the value for the key that corresponds to the right colour.
I am getting this error:
userinput == input(color_key)
NameError: name 'userinput' is not defined
Can anyone help me please.
Based on assumptions that you want to make kind of "memory" game with colors and integers, code proposal for your game would be something like this:
import random
d = {'Red': 1, 'Green': 2, 'Blue': 3}
while 1==1:
rand1 = random.choice(list(d))
user_input = input("Please guess the code of "+rand1+" color:\n")
try:
int(user_input)
if(int(user_input) == d[rand1]):
print("Color code is correct!")
else:
print("Color code is incorrect!")
except ValueError:
if(user_input.lower() == "quit"):
print("Program will terminate now")
else:
print("Invalid input provided.")
Take in consideration few things important for these kind of exercises:
Despite python is not strictly typizied language, you have to take
care of exceptions in the user input
"While 1==1" generates something
called "dead loop". Make sure you always have exit condition for this
one - In our case out here, that is keyword "quit" on the input.
In case of keyword "quit" on the input, it has to be validated for both
upper and lowercase
EDIT:
According to your newest update, I am providing you the example of simple 3-operations based game:
import random
def detect_string_operation(elem1, elem2, operator):
result = ""
if(operator == "+"):
result = str(elem1 + elem2)
elif(operator == "-"):
result = str(elem1 - elem2)
elif(operator == "*"):
result = str(elem1 * elem2)
elif(operator == "/"):
result = str(elem1/elem2)
return result
operators_list = ["+", "-", "*"]
while 1==1:
elem1 = random.randint(0, 10)
elem2 = random.randint(0, 10)
operator_index = random.randint(0, len(operators_list)-1)
result_operation = detect_string_operation(elem1, elem2, operators_list[operator_index])
user_input = input("Please calculate following: "+str(elem1)+str(operators_list[operator_index])+str(elem2)+"=")
try:
int(user_input)
if(user_input == result_operation):
print("Result is correct!")
else:
print("Result is incorrect!")
except ValueError:
if(user_input.lower() == "quit"):
print("Program will terminate now")
break
else:
print("Invalid input provided.")
Note that I didn't implement division for a reason: for division totally random choice of values is not an option, since we need an integer as a result of division. Algorithm for generating divisor and divider pair is quite simple to be implemented in iterative way, but it is out of scope of your initial question.

def function to compare two strings

we need to define a function that compares two strings and if they are different we want to know the index. the problem is that no matter what insert we use we always get -1 even when they are not the same.
def mutation_detector(seq1,seq2):
if DNAval(seq1) and DNAval(seq2) == True:
if len(seq1) == len(seq2):
for i in range(0, len(seq1)) and range(0, len(seq2)):
if seq1[i] != seq2[i]:
return(i)
else:
return(-1)
else:
return('Wrong input')
else:
return('Wrong input')
print(mutation_detector('ATCGGGTA','ATCGGCTA'))
Basically you're using and wrong and have some basic Logic errors I think:
and doesn't say "do A and B" but rather"if A is True and B is True"
My attempt at fixing it is as follows:
if DNAval(seq1) and DNAval(seq2):
if len(seq1) == len(seq2):
for (i, (elem1, elem2)) in enumerate(zip(seq1, seq2)):
if elem1 != elem2:
return i
return -1
Your if-else in the loop always returns in the First loop iteration: it takes the first two chars and compares them; are they equal? No -> return -1
If you follow the logic, it begins comparing strings. If the two letters are the same, it goes for the ELSE (because they are not different) and ends the routine after checking only the first letter.
You only want the routine to return -1 if it makes it all the way through the for loop without returning an index number. So,
Change as below:
def test(seq1, seq2):
if len(seq1) == len(seq2):
for i in range(0, len(seq1)):
if seq1[i] != seq2[i]:
return(i)
return(-1)
else:
return('Wrong input')
print( test('Hello1', 'Hello2'))
print('done')
The problem is, that you are returning -1 on the first time you run through the for loop, because the else-clause is immediately entered.
Use the else clause with the for loop itself instead.
For example:
def compare_strings(seq1, seq2):
if len(seq1) == len(seq2):
for i in range(0, len(seq1)):
if seq1[i] != seq2[i]:
return i
else:
return -1
else:
return 'Wrong input'
(mind you, raising a custom exception might be better than returning "Wrong input" here...)
Here's how I would do it
def mutation_detector(seq1, seq2):
if not DNAval(seq1) or not DNAval(seq2) or len(seq1) != len(seq2):
return "Wrong input" # maybe raise ValueError if DNAval fails instead?
for index, (base1, base2) in enumerate(zip(seq1, seq2)):
if base1 != base2:
return index
return -1
Try this,
It will return index when unable to compare otherwise it will compare two character and to print equal again compare it with length of string.
def mutation_detector(seq1,seq2):
count=0
if len(seq1) == len(seq2):
for i in range(0, len(seq1)) and range(0, len(seq2)):
if seq1[i] != seq2[i]:
return i
else:
count=count+1
if count==len(seq1):
return 'Equal'
print(mutation_detector('ATCGGCTA','ATCGGCTA'))
def comp_string(string1,string2):
if len(string1)!=len(string2):
return "length not equal"
else:
for i in range(len(string1)):
if string1[i] != string2[i]:
return i
return "equal"

Building a dictionary with lists using recursion

I was trying to build a dictionary with recursion for a school project. Right now I think I have the general structure figured out, but I can't figure out how to get the return statement to concatenate pieces of the dictionary together.
I realize this would probably be easier by constructing an empty dictionary then adding to it, but I wanted to see if there were any tricks I could use.
The output I was looking for is:
print(recur_join([1,2,3], ['a', 'b', 'c']))
>>> {1: 'a', 2 : 'b', 3 : 'c'}
I have tried .update() and something of the form dict(basket_one, **basket_two) from another answer. I may have used them wrong. I am using python 3.
Here is my code as of now:
def recur_join(list1, list2):
if len(list1) == len(list2):
if len(list1) == 1:
return {list1[0]: list2[0]}
elif len(list1) > 1:
# dict(basket_one, **basket_two)
#return dict({list1[0]: list2[0]}, **recur_join(list1[1:],
list2[1:]))
return {list1[0]: list2[0]}.update(recur_join(list1[1:], list2[1:]))
else:
print('lists do not match in size')
return 0
Any help would be appreciated, sorry if this was answered before.
Thanks!
I suggest you don't use recursion and use dict comprehensions instead:
def recur_join(list1, list2):
if len(list1) != len(list2):
print('lists do not match in size')
return
else: return {list1[i]:list2[i] for i in range(len(list1))}
For the recursive route (warning: very ugly):
def recur_join(list1, list2):
if len(list1) != len(list2):
print('lists do not match in size')
return
elif list1 == [] and list2 == []:
return {}
else:
return dict(list({list1[0]: list2[0]}.items()) + list(recur_join(list1[1:], list2[1:]).items()))
"Cleanish" recursive solution. I would personally use Primusa's dictionary
comprehension solution.
def recur_join(list1, list2):
cur = {}
if len(list1) == len(list2) and len(list1) > 0:
cur = {list1[0]: list2[0]}
if len(list1) > 1:
cur.update(recur_join(list1[1:], list2[1:]))
else:
print('lists do not match in size')
return cur

Python rock, paper, scissors game

I am using Python and I am trying to write a simple program that simulates a rock, paper, scissors game. Everything works except for when I enter an invalid response (something other than rock, paper, or scissors) when I get this error.
Traceback (most recent call last):
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 88, in <module>
main()
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 14, in main
number = user_guess()
File "C:/Users/home/Desktop/BAGARDNER/Python/rock_pape_scissors.py", line 48, in user_guess
return number
UnboundLocalError: local variable 'number' referenced before assignment
I understand that this is telling me that number isn't referenced, but from what I understand of the code, it shouldn't need a number when the qualifier is false.
#import random module
import random
#main function
def main():
#intro message
print("Let's play 'Rock, Paper, Scissors'!")
#call the user's guess function
number = user_guess()
#call the computer's number function
num = computer_number()
#call the results function
results(num, number)
#computer_number function
def computer_number():
#get a random number in the range of 1 through 3
num = random.randrange(1,4)
#if/elif statement
if num == 1:
print("Computer chooses rock")
elif num == 2:
print("Computer chooses paper")
elif num == 3:
print("Computer chooses scissors")
#return the number
return num
#user_guess function
def user_guess():
#get the user's guess
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
#while guess == 'paper' or guess == 'rock' or guess == 'scissors':
if is_valid_guess(guess):
#if/elif statement
#assign 1 to rock
if guess == 'rock':
number = 1
#assign 2 to paper
elif guess == 'paper':
number = 2
#assign 3 to scissors
elif guess == 'scissors':
number = 3
return number
else:
print('That response is invalid.')
user_guess()
def is_valid_guess(guess):
if guess == 'rock' or 'paper' or 'scissors':
status = True
else:
status = False
return status
def restart():
answer = input("Would you like to play again? Enter 'y' for yes or \
'n' for no: ")
#if/elif statement
if answer == 'y':
main()
elif answer == 'n':
print("Goodbye!")
else:
print("Please enter only 'y' or 'n'!")
#call restart
restart()
#results function
def results(num, number):
#find the difference in the two numbers
difference = num - number
#if/elif statement
if difference == 0:
print("TIE!")
#call restart
restart()
elif difference % 3 == 1:
print("I'm sorry! You lost :(")
#call restart
restart()
elif difference % 3 == 2:
print("Congratulations! You won :)")
#call restart
restart()
main()
Thank you for your help!
Here's your problem:
if guess == 'rock' or 'paper' or 'scissors':
This line in is_valid_guess doesn't do what you think it does. Instead, it always returns True. What you're looking for is something like this:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
or more concisely:
if guess in ('rock', 'paper', 'scissors'):
The problem is that what you have always returns True because of how Python evaluates strings in a boolean context. The line if guess == 'rock' or 'paper' or 'scissors': evaluates as:
if (guess == 'rock') or ('paper') or ('scissors'):
What this means is that Python checks to see if guess == 'rock'. If that's true, the conditional evaluates to True. If it's false, the interpreter tries to evaluate bool('paper'). This always evaluates to True because all non-empty strings are "truthy". Therefore, your whole conditional is always True, and every string is "valid".
As a result, your code considers all strings "valid" and then blows up when it fails to assign a number to a guess that is not actually supported.
As a final note, your is_valid_guess method could be trimmed a bit, since you're just returning the result of your boolean expression. Rather than using the status variable as an intermediate, you can just compute the expression and return it right away. I also use the lower() method of string objects to allow for case-insensitive guessing, in case that's something you want to allow.
def is_valid_guess(guess):
return guess.lower() in ('rock', 'paper', 'scissors')
You've got another issue, which you mentioned in the comments: you've implemented user_guess in a recursive fashion, so that it calls itself if the user enters an invalid guess. However, in this case, it does not return the result of the recursive call. You need to either return the recursive result by changing the last line of user_guess to:
return user_guess()
Or else you should make that function use a loop instead of recursion, which is what I would do, since the function is not inherently recursive. You can do something like this:
def user_guess():
# get first guess
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# If that guess is invalid, loop until we get a valid guess.
while not is_valid_guess(guess):
print('That response is invalid.')
guess = input("Choose 'rock', 'paper', or 'scissors' by typing that word. ")
# Now assign the (valid!) guess a number
# This dictionary is just shorthand for your if/elif chain.
guess_table = {
'rock' : 1,
'paper' : 2,
'scissors' : 3
}
# Return the number associated with the guess.
return guess_table[guess.lower()]
Change
if guess == 'rock' or 'paper' or 'scissors':
to
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
In fact, to make the function as streamlined as possible, just do this:
def is_valid_guess(guess):
return guess == 'rock' or guess == 'paper' or guess == 'scissors'
As other users have pointed out, you need to change your validation in is_valid_guess to:
if guess == 'rock' or guess == 'paper' or guess == 'scissors':
While this won't solve your immediate problem, it is good (upvote-worthy) advice, and will let you avoid some errors you would have run into.
Additionally, no matter what the user inputs, you always return what they type in. To prevent this, you must return user_guess() in your else block:
if is_valid_guess(guess):
#if/elif statement
#assign 1 to rock
if guess == 'rock':
number = 1
#assign 2 to paper
elif guess == 'paper':
number = 2
#assign 3 to scissors
elif guess == 'scissors':
number = 3
return number
else:
print('That response is invalid.')
return user_guess() # <-- right here
Just change input to raw_input

Resources