While loop doesn't work/loops forever | Beginner question [duplicate] - python

This question already has answers here:
How can I read inputs as numbers?
(10 answers)
Closed 1 year ago.
Below is my attempted solution to this problem: The top prize in a lottery is won by matching three numbers between 1 and 30 to three random numbers drawn in the same order. When a ball is drawn it is put back into the machine before another ball is drawn. There are always 30 balls in the machine before a ball is drawn and a player may choose the same ball more than once. A draw takes place once a week. Write a function that takes three numbers as parameters, draws three random numbers between 1 and 30 and returns the number of weeks it took to win the jackpot. (E.g. Numbers chosen: 17, 12, 25 must match: ball one is 17, ball two is 12, ball three is 25.)
My attempt:
import random
chosen = []
for i in range(0, 3, 1):
chosen.append(input("Please input your lucky number: "))
drawn_numbers = []
count = 0
week_count = 0
print("Your chosen numbers are: {}, {}, {}".format(chosen[0], chosen[1], chosen[2]))
while count != 3:
for i in range(0, 3, 1):
random_number = random.randint(1, 30)
drawn_numbers.append(random_number)
for i in range(0, 3, 1):
if drawn_numbers[i] in chosen:
count += 1
week_count += 1
drawn_numbers = []
print("It took you {} weeks to win.".format(week_count))
For some reason the while loop just ignores the count += 1 part and loops randomly generated drawn_numbers lists forever.
Obviously there is something wrong with my loop, but I can't see it D:
Some advice on how to make that loop work would be nice. Thanks.

First of all - welcome to the world of Python!
You have several mistakes:
The input function returns a string and not an int. Meaning, the comparison you try to do implicitly in if drawn_numbers[i] in chosen would never be true, thus count is always 0 and you got yourself an infinite loop.
Assuming that you've fixed the mistake above, you still have a chance of count never hitting 3 at the evaluation of the loop. Consider the following scenario:
A user enters the numbers [1, 2, 3]
The drawn_numbers are [1, 2, 4]
Thus, count will be now 2
The while condition is count != 3 is True and thus the loop continues.
The numbers are drawn again are [1, 2, 4]
The count will be now 4
From now on, count can only increase and will never be equal to 3!
Do you see where this is going? Try to reset the count at the start of loop (inside)!
a lottery is won by matching three numbers ... in the same order
But the comparison you've implemented only looks for existence in the list instead of comparing element by element.
So, a working (not written in the most Pythonic way) version will be:
import random
chosen = []
for i in range(0, 3, 1):
chosen.append(int(input("Please input your lucky number: "))) # notice the int cast
drawn_numbers = []
count = 0
week_count = 0
print("Your chosen numbers are: {}, {}, {}".format(chosen[0], chosen[1], chosen[2]))
while count != 3:
count = 0 # notice that count is reset here
for i in range(0, 3, 1):
random_number = random.randint(1, 30)
drawn_numbers.append(random_number)
for i in range(0, 3, 1):
if drawn_numbers[i] == chosen[i]: # notice that we compare the elements in the same location
count += 1
week_count += 1
drawn_numbers = []
print("It took you {} weeks to win.".format(week_count))
If you're interested, here is a more Pythonic way:
import random
chosen = [int(input("Please input your lucky number: ")) for _ in range(3)]
print(f'Your chosen numbers are: {chosen}')
matched = False
week_count = 0
while not matched:
drawn_numbers = [random.randint(1, 30) for _ in range(3)]
matched = drawn_numbers == chosen
week_count += 1
print(f"It took you {week_count} weeks to win.")
In which you might find several features that might be new to you but I strongly encourage you to master them:
List comprehension
range(3) is equivalent to range(0, 3, 1)
Formatting string literals
The == operator actually compares two lists element by element!
Funny side note: Running this code without the order restriction results in much less weeks to wait to win the lottery :)

Have you checked your if-statement ever becomes true?
One thought is, that chosen might includes string-values as numbers. Try running:
print(type(chosen[0]))
This should be a int. Fix it by:
chosen.append(int(input("Please input your lucky number: ")))

Related

Count occurence of largest number using python [duplicate]

This question already has answers here:
Get a list of numbers as input from the user
(11 answers)
Closed 5 months ago.
Suppose that you entered 3 5 2 5 5 5 0 and input always ends with the number 0, the program finds that the largest number is 5 and the occurrence count for 5 is 4.
Input: i enter 3 5 2 5 5 5 0 and it shows nothing as result
Code:
currentnum = int(input('Enter Numbers List, to end enter 0: '))
maxx = 1
while currentnum > 0:
if currentnum > maxx:
max = currentnum
count = 1
elif currentnum == maxx:
count += 1
print('The Largest number is:', int(maxx), 'and count is', int(count))
Python doesn't have thunks.
currentnum = int(input('Enter Numbers List, to end enter 0: '))
This sets currentnum to the result of running int on the value returned by the input call. From this point on, currentnum is an int.
while currentnum > 0:
if currentnum > maxx:
max = currentnum
count = 1
elif currentnum == maxx:
count += 1
In this loop, you never take any more input, or reassign currentnum, so the loop will carry on forever, checking the same number over and over again.
If you assigned to currentnum at the end of your loop, you could take input in one-number-per-line. However, you want a space-separated input format, which can be better handled by iterating over the input:
numbers = [int(n) for n in input('Enter numbers list: ').split()]
max_num = max(numbers)
print(f"The largest number is {max_num} (occurs {numbers.count(max_num)} times)")
(Adding the 0-termination support is left as an exercise for the reader.)
Another, similar solution:
from collections import Counter
counts = Counter(map(int, input('Enter numbers list: ')))
max_num = max(counts, key=counts.get)
print(f"The largest number is {max_num} (occurs {counts[max_num]} times)")
I recommend trying your approach again, but using a for loop instead of a while loop.
Okay. So one of the most important things to do while programming is to think about the logic and dry run your code on paper before running it on the IDE. It gives you a clear understanding of what is exactly happening and what values variables hold after the execution of each line.
The main problem with your code is at the input stage. When you enter a value larger than 0, the loop starts and never ends. To make you understand the logic clearly, I am posting a solution without using any built-in methods. Let me know if you face any issue
nums = []
currentnum = int(input('Enter Numbers List, to end enter 0: '))
while currentnum > 0:
nums.append(currentnum)
currentnum = int(input('Enter Numbers List, to end enter 0: '))
max = 1
count = 0
for num in nums:
if num > max:
max = num
count = 1
elif num == max:
count += 1
print('The Largest number is:', max, 'and count is', count)
Now this can not be the efficient solution but try to understand the flow of a program. We create a list nums where we store all the input numbers and then we run the loop on it to find the max value and its count.
Best of luck :)
Use the standard library instead. takewhile will find the "0" end sentinel and Counter will count the values found before that. Sort the counter and you'll find the largest member and its count.
import collections
import itertools
test = "3 5 2 5 5 5 0 other things"
counts = collections.Counter((int(a) for a in
itertools.takewhile(lambda x: x != "0", test.split())))
maxval = sorted(counts)[-1]
maxcount = counts[maxval]
print(maxval, maxcount)
to make sure that operation stops at '0', regex is used.
counting is done by iterating on a set from the input using a dict comprehension.
import re
inp = "3 5 2 5 5 5 0 other things"
inp = ''.join(re.findall(r'^[\d\s]+', inp)).split()
pairs = {num:inp.count(num) for num in set(inp)}
print(f"{max(pairs.items())}")
Why not do it this way?
print(f"{max(lst)} appears {lst.count(max(lst))} times")

Looking for Clarification on how this "For-Loop" works

I'm a complete beginner to programming so forgive me for my naivete.
I wanted to make a program in Python that lets me print a given N number of prime numbers, where N is inputted by the user. I searched a little on "for/while" loops and did some tinkering. I ran a program I saw online and modified it to suit the problem. Here is the code:
i = 1
print("Hi! Let's print the first N prime numbers.")
nPrimes = int(input("Enter your N: "))
counter = 0
while True:
c = 0 #another initialization
for x in range (1, (i + 1)):
a = i % x # "a" is a new variable that got introduced.
if a == 0:
c = c + 1
if c == 2:
print(i, end = " ")
counter = counter + 1
if counter > = nPrimes: #if it reaches the number input, the loop will end.
break
i = i+1
print(": Are your", nPrimes, "prime number/s!")
print()
print("Thanks for trying!")
This should be able to print the amount of prime numbers the user so likes. It is a working code, though I am having difficulty trying to understand it. It seems that the variable c is important in deciding whether or not to print the variable i (which in our case is the supposed prime number during that interval).
We do c + 1 to c every time our variable a has a remainder of 0 in a = i % x. Then, if c reaches 2, the current variable i is printed, and variable c re-initializes itself to 0 once a prime number has been found and printed.
This I can comprehend, but I get confused once the numbers of i get to values 4 and onwards. *How is 4 skipped by the program and not printed when it has 2+ factors in the range that makes its remainder equal to zero? Wouldn't c == 2 for 4 and thus print 4? *And how would the program continue to the next number, 5? (Given that variable N is a large enough input).
Any clarifications would be greatly appreciated. Thank you so much!
From Wikipedia we know:
A prime number (or a prime) is a natural number greater than 1 that cannot be formed by multiplying two smaller natural numbers.
So to find a prime, is to find a natural number, aka an integer, which can only be exactly divided by 1 or itself. This is called Approach of Definition to find primes.
Hence, the following loop traverses through all integers from 1 to i,
and it counts how many times the integer i can be exactly divided by them.
for x in range (1, (i + 1)):
a = i % x # "a" is a new variable that got introduced.
if a == 0:
c = c + 1
And later you judge if the integer i can only be exactly divided by 1 and itself.
If true, you got a prime;
otherwise you just keep on.
if c == 2:
print(i, end = " ")
counter = counter + 1
if counter > = nPrimes: #if it reaches the number input, the loop will end.
break
Meanwhile, you can improve this prime searching algorithm a little bit by changing i = 1 to i = 2 in the beginning and adding an if statement:
# Start from 2 instead of 1
# and end at `i - 1` instead of `i`
for x in range (2, i):
a = i % x # "a" is a new variable that got introduced.
if a == 0:
c = c + 1
# Abandon the loop
# because an integer with factors other than 1 and itself
# is unevitably a composite number, not a prime
if c > 0:
break
if c == 0:
print(i, end = " ")
counter = counter + 1
if counter >= nPrimes: #if it reaches the number input, the loop will end.
break
This twist improves the efficiency of your program because you avoid unnecessary and meaningless amount of work.
To prevent potential infinite loop resulting from while expression,
you should replace while True: with while counter < nPrimes:. And the code turns out to be like this:
#if it reaches the number input, the loop will end.
while counter < nPrimes:
c = 0 #another initialization
# Start from 2 instead of 1
# and end at `i - 1` instead of `i`
for x in range (2, i):
a = i % x # "a" is a new variable that got introduced.
if a == 0:
c = c + 1
# Abandon the loop
# because an integer with factors other than 1 and itself
# is unevitably a composite number, not a prime
if c > 0:
break
if c == 0:
print(i, end = " ")
counter = counter + 1
i = i + 1
If you want to read more about how to improve your program's efficiency in finding primes, read this code in C language. :P
c in this case is used to count the number of numbers that divide evenly into i.
for example, if i = 8: 8 is divisible by 1, 2, 4, and 8. so c = 4 since there are 4 things that divide evenly into it
if i = 5: 5 is divisible by 1 and 5. so c = 2 since there are 2 numbers that divide evenly into it
if i = 4 (where you seem to be confused): 4 is divisible by 1, 2, and 4. so c = 3, not 2.

Finding all numbers that evenly divide a number

So I'm trying to make a program that when I input a number it will give me all the factors(12->1,2,3,4,6,12). I only started programming very recently so there may be some very obvious things. But here's my code
numbers = [1]
newnum = 1
chosen = int(input("Enter what you want the factors of: "))
def factors(numbers,newnum,chosen):
lastnum = numbers[-1]
if (chosen == lastnum):
for number in numbers:
if (number % 1 != 0):
numbers.remove(number)
print (numbers)
else:
factors(numbers,newnum,chosen)
else:
newnum = numbers[-1] + 1
numbers.append(newnum)
print (numbers)
factors(numbers,newnum,chosen)
factors(numbers,newnum,chosen)
Ok, so I don't really need the redundancies addressed but if you see something that would completely stop the program from working please point it out. Sorry I bothered you all with this but I don't know what else to do.
There are lots of problems:
Every integer number modulo 1 is zero because each integer is divisible by one without remainder.
You remove items from the list you're iterating over, that will definetly give wrong results if you don't do it carefully!
You try to do recursion but you don't return the result of the recursive call. That's possible because you operate on a mutable list but it's generally not really good style
You don't have any inline comments explaining what that line is supposed to do, so it's hard to give any reasonable guidance on how to improve the code.
If you want a code that finds all factors, consider something like this:
chosen = int(input("Enter what you want the factors of: "))
def factors(chosen, currentnum=None, numbers=None):
# Recursion start, always append 1 and start with 2
if numbers is None:
numbers = [1]
currentnum = 2
# We're at the last value, it's always divisible by itself so
# append it and return
if currentnum == chosen:
numbers.append(currentnum)
return numbers
else:
# Check if the chosen item is divisible by the current number
if chosen % currentnum == 0:
numbers.append(currentnum)
# Always continue with the next number:
currentnum += 1
return factors(chosen, currentnum, numbers)
>>> factors(chosen)
Enter what you want the factors of: 12
[1, 2, 3, 4, 6, 12]
That's not the optimal solution but it uses recursion and gives a proper result. Just don't enter negative values or catch that case in the function at the beginning!
# Two Pointer Approach
ans = []
def divisor(val):
result = []
for i in range(1, val + 1):
ans.append(i)
i = 0
j = len(ans) - 1
while i < j:
if ans[i] * ans[j] == ans[-1]:
result.append(ans[i])
result.append(ans[j])
i += 1
else:
j -= 1
return sorted(result)
print(divisor(12))
# Output
>>> [1, 2, 3, 4, 6, 12]

Program that simulates rolling a dice, and tells you how many times you roll each number

I am a beginner programer, and I have to create a program that simulates rolling a dice 10000 times, and then tells the user how many times they rolled each number. The hard part is, I have to do it using only two variables.
import random
count1=0
count2=0
count3=0
count4=0
count5=0
count6=0
dice=random.randint(1,7)
for i in range(10000):
if dice==1:
count1+=1
if dice==2:
count2+=1
if dice==3:
count3+=1
if dice==4:
count4+=1
if dice==5:
count5+=1
if dice==6:
count6+=1
print "You entered "+ str(count1)+ " ones, " + str(count2) + " twos, "+str(count3) + " threes, " +str(count4)+ " fours, " +str(count5)+ " fives, and "+str(count6) +" sixes."
The problem is, I can't get the program to pick more than one random number, it will just repeat the same number 10000 times. Also, as you can see, I have no idea how to write this program with only two variables, but I think it may have something to do with lists.
You need to put the line dice=random.randint(1,7) inside the for loop.
Your immediate problem is that you get a random value once before the loop starts, and then use that single value each time through the loop. To fix this, the call to random.randint() should be moved inside the loop:
for i in range(10000):
dice=random.randint(1,7)
if dice==1:
Secondly, the call as you have it will give you numbers between one and seven inclusive which, unless you're using some weird Dungeons and Dragons style dice, is probably not what you want. You should be generating numbers from one to six inclusive or, as per below with the arrays, zero through five.
Thirdly, if you're limited to two variables, it's almost a guarantee that you'll use those up with a loop counter and an array of count values, leaving nothing left over for the dice throw and individual count variables.
So you'll need something like the following pseudo-code:
dim count[1..6]
for i = 1 to 6 inclusive:
count[i] = 0
for i = 1 to 10000 inclusive:
count[random(1..6)] += 1
for i = 1 to 6 inclusive:
output "Dice value ", i, " occurred ", count[i], " times."
If this is classwork, I urge you to stop reading now and implement your own solution based on that. If it's not classwork, or your ethics aren't as strong as they could be (a), the Python code below shows one way of doing it, keeping in mind that Python arrays are zero-based rather than one-based:
import random
count = [0, 0, 0, 0, 0, 0]
for i in range(10000):
count[random.randint(0,5)] += 1
for i in range(6):
print "Value %d happened %d times" % (i + 1, count[i])
(a) Just be aware that SO is a fairly well known site and your educators may well be checking classwork against things they find on the net.
you can use a dictionary:
import random
from collections import defaultdict
dice = defaultdict(int)
for x in range(10000):
dice[random.randint(1,6)] += 1
print(dice)
import random
one = 0
two = 0
three = 0
four = 0
five = 0
six = 0
for i in range(10000):
dice = random.randint(1, 7)
if dice == 1:
one += 1
if dice == 2:
two += 1
if dice == 3:
three += 1
if dice == 4:
four += 1
if dice == 5:
five += 1
if dice == 6:
six += 1
print(one, two, three, four, five, six)
Because you put dice=random.randint(1,7) outside the loop which of course will always only generate one number.
I will put code for 'only two variables' later. Looks like an interesting question.

Python dice rolling simulation

I'm having trouble with a code where I need to roll a six-sided die 1000 times and then return a list of how many times each number on the die was rolled.
The code runs just fine and I can get a list at the end, but my list keeps having 0 in place of four so it appears that my function is not keeping tabs on the number 4 being rolled or it's not being rolled at all.
I'm kind of stumped and I thought maybe someone here could help. Any and all help is appreciated.
Here's my code.
def rollDie(number):
one = 0
two = 0
three = 0
four = 0
five = 0
six = 0
for i in range(0, number):
roll=int(random.randint(1,6))
if roll == 1:
one = one+1
elif roll == 2:
two = two+1
elif roll == 3:
three = three+1
elif roll == 4:
four == four+1
elif roll == 5:
five = five+1
elif roll == 6:
six = six+1
return [one,two,three,four,five,six]
You have a small typo; you are testing for equality, not assigning:
four == four+1
should be:
four = four+1
However, you already have a number between 1 and 6, why not make that into an index into the results list? That way you don't have to use so many if statements. Keep your data out of your variable names:
def rollDie(number):
counts = [0] * 6
for i in range(number):
roll = random.randint(1,6)
counts[roll - 1] += 1
return counts
I can't improve on Martijn Pieters's answer. :-) But this problem can be more conveniently solved using a list.
import random
def rollDie(number):
# create a list with 7 values; we will only use the top six
rolls = [0, 0, 0, 0, 0, 0, 0]
for i in range(0, number):
roll=int(random.randint(1,6))
rolls[roll] += 1
return rolls
if __name__ == "__main__":
result = rollDie(1000)
print(result[1:]) # print only the indices from 1 to 6
And, this is a little bit tricky, but here is a better way to create a list of 7 entries all set to zero:
rolls = [0] * 7
Why count the zeros yourself? It's easier to just make Python do the work for you. :-)
EDIT: The list is length 7 because we want to use indices 1 through 6. There is also a position 0 in the list, but we don't use it.
Another way to do it is to map the dice rolls onto indices. It's a pretty simple mapping: just subtract 1. So, a die roll of 1 would go into index 0 of the list, a die roll of 2 would go into index 1, and so on. Now we will use every position in the list.
Here's that version:
import random
def rollDie(number):
rolls = [0] * 6
for i in range(0, number):
roll=int(random.randint(1,6))
rolls[roll - 1] += 1
return rolls
if __name__ == "__main__":
result = rollDie(1000)
print(result)
You should do random.randint(1, 7), otherwise you will never get a 6.
...
roll = random.randint(1, 7)
import random
def dice():
print random.randint(1,6)
dice()

Categories