Python progroam, Exclude Groups - python

kicked = 0
def calculate():
room = 0
global kicked
N = input("Write the number of groups\n")
M = input("Write the size of the groups, separated with space:\n").split()
for elem in M:
if room+int(elem)<int(N)+1:
room += int(elem)
else:
kicked += 1
while True:
try:
calculate()
print(kicked, "groups did not fit")
break
except:
print("An exception occurred, try again:\n")
Mainly I need help to explain my for loop.
secondly I can't use a splitter input on my first input, why?

Transforming the previous comment into an answer, and adding some optimization hints that would not fit in a comment:
Asking for help "to explain my for loop" is a bit unusual - it's your loop, you should know what it does :D Anyhow it basically checks if the sum of all elements in M insofar is still less than or equal to N; if not it "kicks" every remaining elements. Not the most efficient way to do that, but it works. For the second question: you surely can use split() on your first input, but you will get a list, not a single value - so you will need to do something like int(N[0]) to get the number.
Optimizations:
casting a string to an int is not particularly slow, but there is no need to repeat the same operation many times. So let's convert N to int once and for all:
N = int(input("Write the number of groups\n"))
for the same reason, let's convert each elem to int once, not twice, and while we're here let's test for less or equal instead of adding 1 and testing for less than (this last point will only give a very slight improvement but improves readability):
for elem in M:
e = int(elem)
if room + e <= int(N):
room += e
finally once we kick a group there's no need to continue looping - we are kicking everything else. So let's compute how many groups we are kicking and exit the loop:
for i,elem in enumerate(M):
e = int(elem)
if room + e <= int(N):
room += e
else:
kicked = len(M) - i
break

Related

Happy Numbers doesn't update variable

I've been coding for about 3 months. Could someone help me understand why my code isn't working? I could look up the answer, but I'd really like to figure out what is going wrong. It runs perfectly the first time through the code, but while it is While-Looping, x always stays as the number inserted into the function. Thanks for your help! The assignment and code is below (for an Udemy class).
Happy Numbers -
A happy number is defined by the following process. Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers, while those that do not end in 1 are unhappy numbers. Display an example of your output here. Find first 8 happy numbers.
def find_happy_number(x):
#we need a bunch of lists
digit_list = []
squared_list = []
result_list = []
happy_numbers = []
unhappy_numbers = []
while True:
#break our number into digits
x = str(x)
for digit in x:
digit_list.append(int(digit))
#square each digit and store in list
for digit in digit_list:
squared_digit = digit**2
squared_list.append(squared_digit)
#adds all numbers on that list
result = sum(squared_list)
print(result)
#check to see if it is a happy number
if result == 1:
print(f'{x} is a happy number!')
break
#check to see if it is an un-happy number
if result in result_list:
print(f'{x} is an UN-happy number!')
break
#if it isn't we continue the churning.
#adds result to result list to see if we are looping infinitally
x = result
result_list.append(result)
`
The PROBLEM is that you are not resetting digit_list and squared_list in every loop, so they just keep getting bigger and bigger. Move their initialization into the while loop, or use a list comprehension instead of a loop.
Consider this for your loop:
while True:
digit_list = [int(digit) for digit in str(x)]
squared_list = [digit**2 for digit in digit_list]
Now you don't need to initialize them. Or, for extra fun, combine it all into one:
while True:
result = sum(int(digit)**2 for digit in str(x))

Python: Loop to check if an input is valid or not line by line

Given the following inputs that simulate a grid with the respective dimensions:
totLines = int(input("Indicate the number os lines: "))
totColunms = int(input("Indicate the number of columns: "))
I want to check whether the input is valid or not (every digit must be between 0 and 20). The code should check each line of the grid and tell the user if the input is valid and if not ask for another input. The problem is that my code only checks the first digit of line1, the second digit of the line2, and so on. For instance, in a 3x3 grid, if I input the following numbers for line1 (separated by spaces) - 21 10 10 - the code is gonna tell me that the input is not valid, but if I put the incorrect digit in position 2 - 10 21 10 - the code is not gonna find any problem. I know the problem must be related to how I´m doing the loop but I can´t understand how to solve this. This is something easy to do but It´s my first time learning a programming language and I still have a lot to learn. Thanks!
for lin in range (1, totLines+1):
print("Line", str(lin))
while True:
sMoves = input("Movement for this line: ")
listMoves = sMoves.split()
listMovesINT = list(map(int, listMoves))
if listMovesINT[lin-1] > 0 and listMovesINT[lin-1] <= 20:
break
else:
print ("Not a valid integer")
continue
I'd suggest putting the logic to get a valid list of moves in its own function, using all() to test all the values in the list (you don't need the current value of lin or anything else in the main loop to figure this out, and putting this task in its own function makes it easier to focus on it without accidentally mixing in other parts of your program):
def get_movement() -> list[int]:
"""Get a list of movement values between 1 and 20."""
while True:
try:
moves = [int(n) for n in input("Movement for this line:").split()]
if not all(1 <= n <= 20 for n in moves):
raise ValueError("all values must be between 1 and 20")
return moves
except ValueError as e:
print("Not a valid integer:", e)
and then in your main loop you can do:
for lin in range (1, totLines+1):
print("Line", lin)
moves = get_movement()
# do whatever thing with moves
As you noticed, you are "binding" the items in your input to your "board" (sort of the "board"... the totLines variable).
But you really just want to verify one input at a time, right? When the user writes the set of movements for any given line, it doesn't really matter whether it's for the first line of the "board" or for the last. Maybe you want the line index to display a nice prompt message, but that's about it. When it comes to ensuring that the input is valid, you really don't need the line for anything, isn't it?
So it all boils down to verifying that the inputs for any given line are valid, and keep pestering the user until they (all) are. Something like:
valid_input = False
while not valid_input:
sMoves = input("Movement for this line: ")
listMoves = sMoves.split()
listMovesINT = list(map(int, listMoves))
valid_input = all((0 < move <= 20) for move in listMovesINT)
if not valid_input:
print("One of the movements is not valid")
If you wanna use the number of total lines (totLines) to show a little bit more human-friendly prompt and then make the code a bit more like what you have it (with a for loop), you can just wrap the while not valid_input like this:
totLines = int(input("Indicate the number os lines: "))
for lineNum in range(1, totLines + 1):
valid_input = False
while not valid_input:
sMoves = input(f"Movement for line {lineNum}: ")
listMoves = sMoves.split()
listMovesINT = list(map(int, listMoves))
valid_input = all((0 < move <= 20) for move in listMovesINT)
if not valid_input:
print("One of the movements is not valid")
First, your code only check one integer per line.
You have an index but it is a line index (lin-1), not a number index.
Was the "while True" supposed to iterate over numbers. If yes, it should be after the "split()".
Here's a working example:
matrix = []
totlines=3
for i in range( totlines):
line = input( "... ")
numbers = [ int( text) for text in line.split()] # convert list of asciiNumbers to list of 3 integers
for number in numbers:
if (number <= 0) or (number>20):
print( "Invalid number in line", i, ":", numbers)
matrix.append( numbers)
print( matrix)

A program that uses while loop to find average of numbers inputted, and uses a break statement to exit the loop

I would like to write a program that uses a while loop to repeatedly prompt the user for numbers and adds the numbers to a running total. When a blank line is entered, the program should print the average of all the numbers entered. I also would like to use a break statement to exit the while loop.
My Incorrect Work:
y = "\n"
total = 0
k = 0
while True:
x = input("Enter your number here: ")
x = float(x)
total = total + float(x)
k = k + 1
if type(x) != int:
print(total/k)
break
Be aware that the function input() will always outputs a string, so type(input()) != int will always be true.
Try using try-except function, when there is ValueError (example unable to convert blank/letters to float), the exception will be raised and break the loop:
total = 0
k = 0
while True:
x = input("Enter your number here: ")
try:
total += float(x)
k += 1
except ValueError:
if k > 0: #to avoid division by zero
print("Average: ", total/k)
break
Output:
Enter your number here: 3
Enter your number here: 4
Enter your number here: 5
Enter your number here:
Average: 4.0
Bearing in mind the comments already made, here is one such way to perform your task and finishing up when a blank entry is encountered.
total = 0.0
k = 0.0
while True:
x = input("Enter your number here: ")
if (x == " "): # Check for a blank line entry here before attempting to convert to float
print("Average is:", (total/k))
break
x = float(x)
total = total + float(x)
k = k + 1
As noted in the comments, one should check for the blank line entry prior to attempting to convert the entry.
You are immediately casting the value of x that is inputted to a float. So,
if type(x) != int
always is true, meaning the loop breaks after one iteration every time.
Others have already solved your problem in different ways, but I think that explaining our thinking might also be useful.
Currently, your program is not checking correclty the exit condition (empty line is entered instead of a number). When a new line is entered, your program should do one of the two possible scenarios:
when an empty line is entered: print result & exit (break)
else (assume a number is entered): add number to total
No third option is specified, so for now, let's assume that every line will either be an empty line or a number. Will expand it later.
After you decided what to do, the actions should just be easily wrapped in a while True: block - so it should be:
initialize_variables_total_and_count
while True:
read_line
decide_what_to_do:
# in case line was a number
convert_line_to_float
add_float_to_total
increment_count
other_case:
# empty line was entered
calculate_and_print
break
With only two options, you only need to decide once what to do. You can swap around the cases by deciding which condition to check for (and that also results in the other being the "default" behavior for other cases).
It's simpler to check for the line being empty with if line_entered == "":. In this case, any non-empty line is treated like a number, and if it were not one, the float() function will error out and your program crashes.
Checking if a string (the entered line) can be converted to a float is a bit harder. There is just no built-in for that in python, but there is a trick: you can try to convert it to a float, and if that works, it was convertible, and if that errors, it was not. There are other ways too, but this is the simplest - see this question on the topic.
In this case, every number will be added to the total, and every non-number (including the empty line, but also random strings like "asdf") will cause the program to calculate the total and stop.
You can avoid putting both cases into an if-else block by using break or continue. (technicly, you never need to use break or continue, all programs can be written without them. In this case, you could have a boolean variable, named run for example, write while run: and instead of break, do run = False). You can use the fact that both break and continue end the loop early to avoid placing the second case inside an else-block and still have the same behavior (as break and continue already causes skipping the rest of the loop body).
So an example implementation: (testing for == "", not using unstructured control flow)
total = 0
count = 0
run = True
while run:
line = input("Enter your number here: ")
if line == "":
print(total / count)
run = False
else:
total += float(line)
count += 1
I also renamed k to count, x to line and used in-place addition operators.
Another implementation, with break, testing for float with try/except (and re-using that for the entire control flow):
total = 0
count = 0
while True:
line = input("Enter your number here: ")
try:
# order matters here. If the first line errors out, the second won't happen so the count will only be inremented if it was indeed a float
total += float(line)
count += 1
except:
print(f"Average is: {total / count}")
break
Here I removed the run variable, and used a format string to print a bit fancier.
And an example using both continue and break:
total = 0
count = 0
while True:
line = input("Enter your number here: ")
if line != "":
total += float(line)
count += 1
continue
print(f"Average is: {total / count}")
break
You can fancy it a bit with adding more error handling - use three cases:
user entered empty line: print & exit
user entered a number: add to total
user entered something else: ignore line, but tell user what to do
I only provide one example implementation for this, but as you can see, it can be implemented in many ways.
total = 0
count = 0
# good practice to tell the user what to do
print("Average calcuator. Enter numbers one per line to calulate average of, enter empty line to print result & exit!")
while True:
line = input("Enter your number here: ")
if line == "":
print(f"Average is: {total / count}")
break
else:
try:
total += float(line)
count += 1
except ValueError:
print("You should enter a number or an empty line to calculate & exit!")

While n > 1. Decrease n by 1 on each iteration

I'm working on some hackerrank problems and I've looked at a couple of ways to take this input and loop through it.
What is be best alternative to trying to decrease n on each iteration as below (as this doesn't seem to be possible).
first_n = int(raw_input())
def findPercentage(n):
if n > 1:
studentinfo = raw_input()
return studentinfo
n = n - 1
result = findPercentage(first_n)
print result
As I'm knew to this, I understand that my logic might be flawed.
The input is passed as stdin with the first line listing the total number of lines to follow. I will want to perform a single operation on every line after the first line with the exception of the last line where I'd look to perform a different operation.
n= int(input())
studentinfo= {}
for i in range(n):
inputs= raw_input().split(" ")
studentinfo[inputs[0]]= inputs[1:];
This will create a dictionary studentinfo with names as key and list of marks as value.
The first line gives you the number of students N:
n = int(raw_input())
Then you want to loop through your function N number of times:
for i in range(n):
studentinfo = raw_input().split(" ")
print(studentinfo[0])
This will create a list called studentinfo, and this will print the student's name. See where you can go from there.

Finding numbers that are multiples of and divisors of 2 user inputted numbers

I have an assignment for Python to take 2 user inputted numbers (making sure the 1st number is smaller than the second) and to find numbers that are multiples of the first, and divisors of the second.. I'm only allowed to use a while loop (new condition my teacher added today..) I've done it with a for loop:
N_small = int(input("Enter the first number: "))
N_big = int(input("Enter the second number: "))
numbers = ""
if N_small > N_big:
print("The first number should be smaller. Their value will be swapped.")
N_small, N_big = N_big, N_small
for x in range(N_small, N_big+1, N_small):
if N_big % x == 0:
numbers += str(x) + " "
print("The numbers are: ", numbers)
I'm not asking for the answer to how to do this with a while loop - but I just need a hint or two to figure out how to start doing this... Can anyone enlighten me?
Thanks
You can convert any for loop into a while loop trivially. Here's what a for loop means:
for element in iterable:
stuff(element)
iterator = iter(iterable)
while True:
try:
element = next(iterator)
except StopIteration:
break
stuff(element)
Of course that's not what your teacher is asking for here, but think about how it works. It's iterating all of the values in range(N_small, N_big+1, N_small). You need some way to get those values—ideally without iterating them, just with basic math.
So, what are those values? They're N_small, then N_small+N_small, then N_small+N_small+N_small, and so on, up until you reach or exceed N_big+1. So, how could you generate those numbers without an iterable?
Start with this:
element = N_small
while element ???: # until you reach or exceed N_big+1
stuff(element)
element ??? # how do you increase element each time?
Just fill in the ??? parts. Then look out for where you could have an off-by-one error that makes you do one loop too many, or one too few, and how you'd write tests for that. Then write those tests. And then, assuming you passed the tests (possibly after fixing a mistake), you're done.
You don't have to iterate over all the numbers, only the multiples...
small, big = 4, 400
times = 1
while times < big / small:
num = times * small
if big % num == 0: print(num)
times += 1

Categories