What differs in while and for loops? - python

Here is the question from Kaggle.
I tried it using a while loop but I guess I am missing something basic here.
The commented code using while loop is my initiation and the uncommented code is the solution.
Detailed solution given on website is pasted below :
def menu_is_boring(meals):
"""Given a list of meals served over some period of time, return True if the
same meal has ever been served two days in a row, and False otherwise.
"""
# i = 1
# while (i) < (len(meals)-1) :
# if meals[i] == meals[i+1] :
# return True
# else :
# i = i + 1
# return False
for i in range(len(meals)-1):
if meals[i] == meals[i+1]:
return True
return False
# Check your answer
q3.check()
The key to our solution is the call to range. range(len(meals)) would give us all the indices of meals. If we had used that range, the last iteration of the loop would be comparing the last element to the element after it, which is... IndexError! range(len(meals)-1) gives us all the indices except the index of the last element.
But don't we need to check if meals is empty? Turns out that range(0) == range(-1) - they're both empty. So if meals has length 0 or 1, we just won't do any iterations of our for loop.

You can simply use the built-in function any()
def menu_is_boring(meals):
return any(meals[i] == meals[i+1] for i in range(len(meals)-1))
Difference between While and For Loop is simple:
While loops run until you break them or pass in a specific condition
For loops run until the range has ended or when you break them.
A for loop can't run forever, but a while loop can.

The difference between for and while loop:
for-loop are for looping or iterating over containers and/or streams of data, such as lists, and the duration of task to be done over that data is usually determinate by the amount of data in said container or stream.
while loop are for looping or repeating a task an usually undetermined number of times and the duration of task to be done is determined by fulfilling some condition that is usually unrelated to the amount of initial data.
While-loop are the more general of the two, and you can in fact do everything a for-loop does with a while-loop, but doing so is more error prone because you need to keep track of the extra things that a for-loop take care off for you like indexing.
And about your sample code, the only problem with your while-loop version is that you start your index a 1 instead of 0 (list indexes start at 0 in python).
And tho there nothing particularly wrong about you for-loop version, there are way of doing it such that you don't need to keep track of any index like
for a, b in zip(meals, meals[1:]): # using the zip function along with using the slice notation in order to pair the first element with second...
if a == b:
return True
return False
from itertools import pairwise # python 3.10+
for a, b in pairwise(meals): # using the pairwise function to pair the first element with second...
if a == b:
return True
return False
(or their one liner version...)

maybe you can try :
i = 1
while False :
if meals[i] == meals[i+1] :
return True
else :
i = i + 1
return False
but you can make infinite loop.

Related

looping on iterables, return best practice

Every now and then I fall on this pattern when looping through an array:
for a in b:
if a==y:
#do somethinng
return 1
there is no else statement because I need to check the full array for a==y (let's say a is name in a dir list) before returning anything.
It would also be a good idea to return something only if no element in the array fulfills the condition a==y
How should I re organize the code in this sense?
How do I tell the caller if the loop doesn't 'succeed' in finding 'y'?
If you are expecting to encounter y only once or only take into account its first occurrence (given that you have a return statement within the condition), then here's another method:
if any(a == y for a in b):
#do something
return 1
else:
return 0
It would probably be a good idea to return something only if no element in the array fulfills the condition x==b but I don't know how to re organize the code in this sense.
The usual thing is to put the return reflecting the fact that nothing matched after the loop:
for a in b:
if a==y:
#do somethinng
return 1
return 0 # or whatever
In some cases, it may be appropriate to throw an exception after the loop instead, if the fact that nothing matched within the loop is an exceptional condition, not a normal case.
Please be sure to check out navneethc's answer using any as well.

Python: How can I use a for loop to execute my code 5 times?

I am new to python and working on basic functions and conditionals.
Here's an example of 1 function in my code:
def oddEven(oe):
if oe % 2 == 0:
print("number is even")
else:
print("number is odd")
There are 3 total functions in my code (omitted because unnecessary). The first two pass the value of the integer named first, and the last function takes two integer parameters and pass both first and second and checks the result.
Here is how I'm recalling these and checking my code
first = 30
second = 60
oddEven(first)
minutes(first)
relation(first, second)
Instructions say:
Run the program five times using the provided first values and your chosen second values, and check your results. You can alternatively run the program once and use a for loop to execute your code five times.
If the values were for example 23, 33, 14, 31 I could just do:
oddEven(23)
oddEven(33)
oddEven(14)
oddEven(31)
Right? And then do the same for the second function and the third. How could I make a for loop for this?
This is simple way to do this :
list_values = [22,33,14,31]
for value in list_Values:
oddEven(value)
You’re right, you use a for loop in order to do that. The previous answers may have been able to iterate through the list for both the evenOdd and minutes functions, but they didn’t handle the case where you compare two consecutive values for your relation function.
Create a list of 5 numbers and iterate through it. Handling the case where you’re comparing two consecutive numbers against each other can be done with a simple if statement that stops executing once you’ve reached the second to the last element in the list.
If you’re not familiar with lists yet, think of them as ‘containers’ for your data; where you can systematically store and access each piece one at a time.
What’s happening in the code is the for loop iterates through the list one element at a time. The function range(n) takes in a number n, for an argument, and then creates a ‘range’ of numbers from 0 to n - 1.(Ex. range(2) will iterate through the for loop 2 times giving i a value of 0 on the first loop and 1 on the second.
An element from a list can be accessed with this notation: list[i], where i is a number that starts from 0 (therefore accessing the first element of the list) and ranges all the way up to the (length of the list - 1). So to access the third element in a list would be done like so: list[2].
The code below is pretty modular so you can add any amount of numbers to the numbers[] list and it should work, given that there is more then 1 number in the list. It’s a good practice to get in the habit of making your code as modular as possible, instead of hard coding in constants. This is done by passing the (length of the list) to the range(), which allows the for loop to iterate over any size list.
If you add only one number to the list ( ex. numbers = [42]), the only thing that would happen is that the code inside the if statement will not execute, as it requires there to be more than 1 number in the list. The oddEven and minute function should still work though. Go ahead and give that a try! Try adding more than 5 numbers to the list too.
numbers = [23, 33, 14, 21, 42]
for i in range(len(numbers)):
first = numbers[i]
oddEven(first)
minutes(first)
if i < (len(numbers) - 1):
second = numbers[i + 1]
relation(first, second)

Is there a cleaner way to handle (consecutive) exclusive if-statement in for-loop?

I'm new to Python (I've only used C) and I've discovered new loops such as for/else... So I wonder if I'm ignoring a cleaner way to handle this loop:
flag = 0
for i in range (n):
if not flag and condition:
statement_1
flag = 1
if flag and condition:
statement_2
I need to keep the for counting, because I know that at least one element will satisfy the condition, so when I find it I'll do statement_1. Then if another element will satisfy the condition as well, I'll do statement_2.
flag = False # I prefer booleans
for i in range(n):
if condition(i): # We always need it to be True
if not flag:
statement(i)
flag = True
else:
statement2(i)
So far this would work, but since you said there is at least one that satisfies the condition
foo = range(n) # any iterable
iterfoo = iter(foo)
initial_value = next(i for i in iterfoo if condition(i))
statement(initial_value)
for i in iterfoo:
if condition(i):
statement2(i)
Now these both, (if I'm not missing something) should do the same thing, just in different ways, so it is your choice, although it also saves you 2 lines of code since you wont be doing the first line in your actual code, so I vote for the second snippet :D

Checking if position in a list of lists is true or false

I'm trying to write a function that analyzes a given list of lists for a specific position and returns True if the position exists and False if it doesn't.
For example, if the list of lists that we'll call "list2" has 7 columns and 5 rows (Basically a list of 5 lists where each list has 7 values and is on its own line), the function should return True if the test case list2[5][4] is run through the function because row 5, and column 4 exists but if the test case list2[8][6] or list2[-5][-1] is run through the function it should return False because row 8 and column 6 don't exist and we can't have negative rows and columns. How could this be accomplished?
This is the code I have so far. When tested it says invalid syntax but I thought I'd include it anyway to help show what my goal is
def in_list(row, col, list):
if list[row][col] == True
return True
else:
return False
If you really want to test for the array item by accessing it, wrap it in a try..except block. If an exception occurs, return False, otherwise return True.
However, there is an easier way--just test that row and col point to a valid entry by using the array's lengths. Here is one way to do that.
def in_list(row, col, lst):
if 0 <= row < len(lst) and 0 <= col < len(lst[row]):
return True
else:
return False
There are more concise ways, but this should be clear. The "short-cut evaluation" in the if line prevents an exception in the check for col if row is not in range. Note that I changed the parameter name from list to lst: using a built-in name is a bad idea. Note that my code does not check if the value of the entry is True or False, as you code seems to try to do--if you want that, it is easy to add that check to my code. Finally, note that my code also works if the rows of the array have differing numbers of columns, which is possible in Python. My code checks only the requested row, which is suitable for this purpose.
Indent your code after if and else. And use colons ":"
def in_list(row, col, list):
if list[row][col] == True:
return True
else:
return False
Once you have fixed your code by adding colons and indenting it as required, you will likely encouter another error: Accessing indices that do not exist is not allowed in python, it doesn't amout to False.
One way of circumventing it would be to enclose your test in a try:... except block.

While loop conditions in: compound conditional expressions AND'd [python]

Apologies for the really trivial introductory level python question.
Currently working through Google Python tutorials and hit something which may trip me up if I don't nail it down - using and'd values as a compound condition for execution of a while loop.
Reading through it appears as if the while loop operates whilst the length of both lists are positive. So once the length of both lists == 0, then the while loop hits a 0 and terminates.
I'm unsure of how to parse this mentally - whether the condition is that once both lengths == 0 then the and statement and's 0 and 0, giving a negative condition and terminates.
Reading it through I parse it as while '5' and '6' (if for instance 5 and 6 are the len of lists). I've not come across use of a while loop in this way so far (only been going for a day or so).
Code bit I don't get (abstract lines)
while len(list1) and len(list2):
Code in context
def linear_merge(list1, list2):
result = []
while len(list1) and len(list2):
if list1[0] < list2[0]:
result.append(list1.pop(0))
else:
result.append(list2.pop(0))
result.extend(list1)
result.extend(list2)
return result
Thanks kindly.
while len(list1) and len(list2):
Will continue to loop while both list1 and list2 are not empty; if either list is empty, the loop will terminate.
(In a boolean context, any value except False, None, 0, "", or [] will evaluate as true.)
Quoting Built In Types Page on Official Python documentation:
x and y give the result according to: if x is false, then x, else y
Further on this page it is mentioned that:
This is a short-circuit operator, so it only evaluates the second argument if the first one is True
So in your question, it first evaluates len(list1). If it is positive, the first condition is True and next it evaluates the second condition. If that is also True (i.e. len(list2)>=1), it enters into the loop. While fundamentally it is an AND operation, it differs in the sense that we don't need to evaluate the second condition, if the first one is False. This can be very helpful in certain cases, when the second condition may involve time consuming calculations.
The key to understanding this is the pop statement.
Basically, the function merges two already-sorted lists into one list containing all elements of both lists. It is a part of the mergesort algorithm. This works as follows:
As long as both lists contain remaining elements, repeat the following loop
select the smaller element from the head of the lists (i.e. the first elements)
remove the element from the respective list and add it to the result list
repeat
Then, at most one of the lists still contains elements. Add the remaining elements of that list to the result.

Categories