Removing objects from a list in python, Attribute error - python

I'm pretty much a complete beginner to python, and i'm having problems removing an integer from a list. I'm getting a error, AttributeError: 'int' object has no attribute 'remove', and i don't know how to fix it. This is probably really easy to experienced eyes, and I have looked at past answers but keep returning same error
repeat = 0
while repeat <= 4:
question_list = [1,2,3,4,5]
number = random.choice(question_list)
if number == 1:
print(question1())
repeat = repeat + 1
number.remove(1)
elif number == 2:
print(question2())
repeat = repeat + 1
number.remove(2)
elif number == 3:
print(question3())
repeat = repeat + 1
number.remove(3)
elif number == 4:
print(question4())
repeat = repeat + 1
number.remove(4)
elif number == 5:
print(question5())
repeat = repeat + 1
number.remove(5)

number = random.choice(question_list) assigns number to an int returned from calling random.choice on your question list. If you want to remove from question_list call remove on the list not number:
question_list.remove(x)
You need to assign question_list outside the while loop, if you put it inside you keep creating a new list so the remove never persists.
question_list = [1,2,3,4,5] # here
while repeat <= 4:
A nicer implementation may be to use a dict and just use range:
import random
# map numbers to functions
questions = {1:question1,2:question2,3:question3,4:question4,5: question5}
question_list = [1, 2, 3, 4, 5] # outside loop
for _ in range(4): # loop in range 4
number = random.choice(question_list)
question_list[func]() # call function using dict key val
question_list.remove(number)
Or simply store the functions in a list and randomly choose one:
question_list = [question1,question2,question3,question4,question5]
for _ in range(4):
func = random.choice(question_list)
func()
question_list.remove(func)

Since a comment already explained why your code doesn't work, I'd like to suggest a simpler alternative.
It seems like you have a few functions you want to call in a random order.
There is no need to complicate things the way you're doing it, and mess around with removing elements from the list.
You can simply have a list of functions, shuffle it, and call every function in order:
questions = [question1, question2, question3, question4, question5]
random.shuffle(questions)
for question in questions:
question()

You should use the remove function on the list, and give the int as a parameter. So it should become:
question_list.remove(something)
But be careful, because if there is no "something" you will get an error.

Related

How to keep track the amount of even integers when looking through randomized list using recursion

Sorta newbie here. So in trying to wrap my head around using recursive functions I wanted to try to make a program that:
1: Generates a list containing 10 random integers ranging from 0 - 20
2: Using a recursive function goes trough the list and finds out what elements of the list are even integers
3: Prints out only the aformentioned even numbers
Where I have gotten stuck is in how to print out the result. I can't seem to figure out what value i want to put inside the function when calling it ( F(?) )
I tried to integrate a counter that kept track on how many times the program found a even number but it always resulted in an error that the variable is not defined no matter how hard I tried to make it global.
How could I go about this? Am I totally in the wrong?
import random
numL = []
for i in range(10):
x = random.randint(0,20)
numL.append(x)
print(numL)
def F(x):
if numL[x] % 2 == 0:
return numL[x]
else:
return F(x+1)
print(F( ??? ))
First question asked on this forum, hopefully I did okay, appreciate any help!
Assuming you want to return a list of the even numbers then you have 4 cases to consider
This is the last number in the list and its even so return this number
This is the last number in the list and its odd dont retrun this number
There are more numbers to check and this number is even so return
this plus the function result
There are more numbers to check and this number is odd to return
only the function result and not this num
So we can code this as
import random
def get_even_nums(nums):
num = nums[0]
#This is our terminating case we definitivly return a value here
if len(nums) == 1:
return [num] if num % 2 == 0 else []
else:
#If we got here we will be recursivly calling the function
#If its even number return that number plus the result of the function
#it its not even then just return the reult of the function and not this num
if num % 2 == 0:
return [num] + get_even_nums(nums[1:])
else:
return get_even_nums(nums[1:])
numL = [random.randint(0, 20) for _ in range(10)]
print(numL)
print(get_even_nums(numL))
OUTPUT
[3, 6, 5, 10, 20, 18, 5, 0, 3, 9]
[6, 10, 20, 18, 0]
So I took your function and changed it up slightly (using a slightly different approach). There's no need to a global list, though you could do that as well, if you wanted. The problem that you have is the lack of a base case or rather an incorrect one.
If you run your original function with an argument 0, which basically is the first element of your generated array, the fucntion will run until it hits one even number. At that point it'll exit recursion, because the base case basically stops recursive calls once you hit an even number.
Now, to fix this, you have to approach the problem differently. I would put your generated array as the input argument to your function, then ask myself "What would be a good base case?" Probably one that stops your recursive calls once you reach the end of the input list.
if len(numL) == 0:
return ...
Also, we need a way to return the even numbers that we found during our search through the list. For that reason I'd introduce a new acc list, where we would append the even numbers that we found. Thus the function input arguments would be
def F(numL, acc):
...
Now, in the recursive call we should check wether the current element is even or not. If it is, great, we add it to the acc list and continue into the recursive call. If it's not, we don't add anything to the acc but just continue with recursion.
if numL[0] % 2 == 0:
acc.append(numL[0])
return F(numL[1:], acc)
Putting it all together, we get:
def F(numL, acc):
if len(numL) == 0:
return acc
else:
if numL[0] % 2 == 0:
acc.append(numL[0])
return F(numL[1:], acc)
where numL represents your generated list and acc represents the resulting list we'll return after we traverse the list.
This is your function (as I understand it, you wanted this):
import random
def F(i):
r = random.randint(0,20)
if r % 2 == 0:
print(r)
i += 1
if i != 10:
F(i)
F(0)

IndexError: list assignment index out of range Python 3

Someone has a Idea why i get an IndexError in this code?
global gegner
global gegnerhp
gegner = []
gegberhp = []
for i in range(1,anzahlgegner):
random = randint(1,5)
if random == 1:
gegner[i] = "goblin"
gegnerhp[i] = randint(10,50)
elif random == 2:
gegner[i] = "ghost"
gegnerhp[i] = randint(10,50)
elif random == 3:
gegner[i] = "hound"
gegnerhp[i] = randint(10,50)
elif random == 4:
gegner[i] = "wolf" #LINE 147
gegnerhp[i] = randint(10,50)
elif random == 5:
gegner[i] = "goblin"
gegnerhp[i] = randint(10, 50)
print("* {0} with {1} HP".format(gegner[i]),gegnerhp[i])
For example when random is 4 i get the following error:
File "C:/Users/Fabio/PycharmProjects/test\dungeon.py", line 147, in run
gegner[i] = "wolf"
IndexError: list assignment index out of range
Maybe my declaration of the list/arrays is wrong?...
There are a number of misconceptions here, and I don't think that addressing just the one you've specifically asked about will be properly helpful, so I'm going to do more than that.
First of all, lists. You're creating empty lists gegner and gegnerhp; it looks like you then want to add some items to those lists, and you're trying to do it by specifying an index. In python, the list index starts from 0, not 1.
i.e. in the following list:
>>> gegner = ["wolf", "hound", "goblin"]
>>> print(gegner[0])
wolf
>>> print(gegner[1])
hound
The index '1' is the second item in the list.
In your code, your range(1,anzhalgegner) would start at 1 and increment up to whatever you have set anzhalgegner to be. In your first iteration, your code attempts to assign a value to the list gegner at position 1 - however, the list does not have anything at position 0, meaning it can't assign anything to position 1.
The simplest change to get you started would be to start your range from 0.
Once you've tried that out, I would also suggest that instead of manually specifying what position in the list to place an item (list[index] = value), since all you are doing is adding things to the end of the list, consider using the append method. Then it would look something like this:
if random == 1:
gegner.append("goblin")
gegnerhp.append(randint(10,50))
You get an IndexError because the lists are empty.
You can't create list items by accessing invalid indices. Use .append isntead.
if random == 1:
gegner.append("goblin")
gegnerhp.append(randint(10, 50))
etc.
your lists gegner and gegnerhp are empty, thus accessing them will give you an error.

Randomly calling functions to execute

I have made this short questionnaire:
from random import randint
def pancakes():
q = raw_input("Do you like pancakes?")
if q == "yes":
print("Great!")
elif q == "no":
print("Hmmm...")
def french_toast():
q = raw_input("Do you like french toast?")
if q == "yes":
print("Oh!")
elif q == "no":
print("Same here!")
def random():
num = 2
while num > 0:
random = randint(1, 2)
if random == 1:
num = num -1
pancakes()
elif random == 2:
num = num -1
french_toast()
random()
My goal here was to get the questions in a random order. But sometimes the same question will be asked twice since it's randomly chosen.
So how can I make it ask the same question only once?
Instead of a while loop, I'd suggest you use a for loop in conjunction with random.sample. Create a list of functions before-hand to provide to sample:
from random import sample
funcs = [french_toast, pancakes]
for func in sample(funcs, len(funcs)):
func()
this will now loop through all functions randomly selecting a function in each iteration.
Alternatively, you could shuffle the list (performs in-place) with random.shuffle and then iterate through it, that will be faster too (though, speed shouldn't be the biggest concern here):
from random import shuffle
funcs = [french_toast, pancakes]
shuffle(funcs)
for func in funcs:
func()
Put these in a function if so required:
from random import shuffle
# use *funcs for passing arbitrary number of
# functions as positional arguments.
def call_funcs_randomly(funcs):
shuffle(funcs)
for func in funcs:
func()
and call them:
call_funcs_randomly([french_toast, pancakes])
As a comment noted, don't use random as a function name, it has the possibility of masking the module random leading to odd looking errors.
I would use random.sample Link. Just create a list of indices to your questions and sample 2 of them.
EDIT:
additionally, you could use random.shuffle Link:
random.shuffle(questions)
for question in questions:
# process your random question once
how about this for your last question (random is not a good name! you might overwrite the module of the same name [although you are fine the way do do it right now])
def random_questions():
eligible_questions = [pancakes, french_toast]
while eligible_questions:
question = random.choice(eligible_questions)
eligible_questions.remove(question)
question()
put the questions in a list, select one with random.choice, remove it from the list and execute it. stop if the question list is empty. this way every question is selected exactly once.
this is easily extended if you want to add more questions.
on second thought: the shuffle version in Jim Fasarakis-Hilliard's answer is a lot cleaner!

How to compare two lists with a while loop

I'm trying to make a script that takes in an answer and appends it to a new list, then checks to see if the new list is the same as the other list. When these lists are the same, the while loop should break.
NOTE: Each question should not repeat.
Here's my code:
import random
questions = ['a','b','c','d','e']
answered_q = []
while len(answered_q) < len(questions):
question = random.choice(questions)
answered_q.append(question)
raw_input = str(input(question + ": "))
if sorted(questions) == sorted(answered_q):
break
When executed I am still getting random questions but the code does not break when the lists have the same contents.
output :
['b','c','b,'d','d']
If anyone can help it would be great!
Thanks in advance!
I think what you really want to do is only append to your new list if the element to be added isn't already in there, so add a check for that.
while len(answered_q) < len(questions):
question = random.choice(questions)
if question not in answered_q:
answered_q.append(question)
raw_input = str(input(question + ": "))
if sorted(questions) == sorted(answered_q):
break
Of course, under this scheme, the loop should end even without the last if-statement because the length of the two lists will be equal by the time the two sorted lists will be equal.
For one, you're getting random questions (and thus orderings), but you are comparing to a set ordering [a,b,c,d].
To solve that with your current implementation, use a set - { "a", "b", "c", "d" }
Though personally, I would just pop things from one list to the other, looping while len(questions) > 0, which guarantees you won't get questions more than once.

Simplifying a short list comparison

Here's the code. It's being used to change a certain value stored in a list (of between 25 and 81 values), depending on the user input. I'm using a second list to decide what happens, with only 4 values inside, which were also the user's input. Basically, if the user chooses a certain value, it changes to the next value in sequence.
if list1[value] == list2[3]:
list[value] = list2[0]
elif list1[value] == list2[0]:
list[value] = list2[1]
elif list1[value] == list2[1]:
list[value] = list2[2]
elif list1[value] == list2[2]:
list[value] = list2[3]
My problem is, I can't find a way to make it simpler. It looks quite long and ugly. It also needs to be executed many times based on extra inputs, so, if the user chose the same variable twice, it would change each time, in sequence.
This seems like such a dumb problem. I've been trying to think of how to simplify this for ages, to a short for loop or something, but for some reason fail every time.
I've tried something like this:
e = value % 4
if list1[value] == list2[e]:
list1[value] = list2[e + 1]
#This isn't exactly what I had, but something along these lines, maybe in a for loop too etc.
List 2 contains 4 string, [colour1, colour2, colour3, colour4]
List 1 contains these same strings, but looped over and over until it hits the list limit specified by user.
Thanks for any help!
Instead of a list for the "cycle" set of data, use a dictionary of {value: nextvalue}, i.e.:
cycler = {0: 1, 1: 2, 2: 3, 3: 0} # replace 0,1,2,3 with the actual values
if list1[value] in cycler:
list1[value] = cycler[list1[value]]
EDIT: To build the cycler from a list of elements:
cycler = {list2[i-1]: list2[i] for i in xrange(len(list2))}
# Note that this works because `list2[-1]` indexes the last element.
for i in range(0, len(list2):
if list1[value] == list2[i] :
list1[value] = list2[(i+1)%len(list2)]

Categories

Resources