not able to understand 2nd while loop in code below-: - python

def summer_of69(arr):
total =0
add = True
for num in arr:
while add:
if num!= 6:
total+=num
break
else:
add = False
while not add:
if num!=9:
break
else:
add= True
break
return total
In this code, if I pass summer_of69([2,5,6,9,11]), how 9 is getting ignored and 11 getting added?
The output I am getting 18 is correct but I want to know how 2nd while loop is working here.
After 6 how is it working for 9 and 11?

In order to understand how any complex system of loops works you just have to go through the code step by step and evaluate the logic the way the computer does.
When num becomes 6, think about what happens when it goes through both while loops.
The first while loop does not add 6 to total and instead turns the variable add to False.
Since add is now False the second while loop triggers but then immediately breaks.
Now num is 9 and since add is False the first while loop does not execute.
Instead the second one does and add becomes True.
Finally, now that add is True, when num is 11, the first while loop executes, adding 11 to the total and the second while loop does not.
It just takes a moment to think it through in your head, and if it ever becomes too complicated to do in your head, there are plenty of visualize execution programs out on the web that do it for you.

Related

How do I get the output using while loop?

I am not getting the output I am expecting. The output should be the sequence of values of less than 6. Is something wrong in the syntax? I think it has very simple error!! I am not getting it.
Write a while loop to display the values of the Rating of an album playlist stored in the list PlayListRatings. If the score is less than 6, exit the loop. The list PlayListRatings is given by: PlayListRatings = [10, 9.5, 10, 8, 7.5, 5, 10, 10]
PlayListRatings=[10,9.5,10,8,7.5,5,20,10]
rating=0
i=0
while rating<6:
rating=PlayListRatings[i]
i=i+1
print(rating)
>>output 10
I think it's easier to use a for loop:
for item in PlayListRatings:
if item < 6:
break
print(item)
If you must use a while loop:
index = 0
while index < len(PlayListRatings) and PlayListRatings[index] > 6:
print(PlayListRatings[index])
index += 1
You define I=0 but then use i=i+1. Python is case sensitive, so you need to use the same casing (i.e. set i=0 instead of I=0).
If the score is less than 6, exit the loop.
This means that your while condition is incorrect. It should be while rating >=6.
I would highly recommend reviewing conditional statements, looping, and basic python syntax.
While loops are generally used when you don't know when the loop is expected to end, for loops are better when you know the loop will end.
In your example you are looping through a list, you are better using a for loop.
Take a look at this:
PlayListRatings=[10,9.5,10,8,7.5,5,20,10]
rating=0
i=0
while i != len(PlayListRatings):
rating = PlayListRatings[i];
if rating < 6: print(rating);
i=i+1;
I know that while loop logic needs some time to get accustomed to. Here is what you need to think of when building a while loop:
When building a while loop: Logic that governs while loop needs to be negative.
## don't run this , it is an infinite loop
iDontWantThis = false; # starting argument
# it is always false, so the loop will go forever
while iDontWantThis == false:
print("I want this");
So when iterating over a list of some kind, the logic that governs when you exit the loop, must not be the same logic that you wish to implement inside the loop. That is main difference between while and for loops.
In your case , your main logic was to print out any element in list that was smaller than 6, so in while loop you need to have logic that is either:
1. For rating that is greater than 6
2. For i index that is smaller than list length
3. Infinite loop with break points inside while loop.
Python is case sensitive : which means that I and i aren't the same variable. But this can happen even to experienced programmers.
Beginner while loop building : when you start learning about while loops. The best course of action is to start with infinite loops, and then implement breaks where you need them. When your code works, then you optimise it so you don't have too much lines and it gets faster.

Trouble understanding break vs else statements with nested loops

I'm practicing python and one of the coding tasks assigned was to create a function that looks through a list and ignores numbers that occur between a 6 and a 9 and returns the sum of all other values.
Edit: this does not mean to add numbers whose values are less than 6 or greater than 9. It means to add all numbers of any value, but to ignore any numbers that come after a 6, until a 9 is seen. Symbolically if i means include and x means exclude, the code should return all the values marked as i:
[i,i...6, x,x,...,9,i,i...,6,x,x,...]
In other words, 6 turns off adding and if adding is off, 9 turns it back on.
Note that a 9 with no preceding 6 is just a number and will be added.
For example if I have a list:
[4,5,6,7,8,9,9]
the output should be:
8 <---(4+5+9)
The solution is provided but I'm having trouble understanding the code. I don't understand the purpose of the break statements in the code. The solution provided is as follows:
def summer_69(*arr):
total = 0
add = True
for num in arr:
while add == True:
if num!=6:
total = total + num
break
else:
add = False
while add == False:
if num !=9:
break
else:
add = True
break
return total
I'm really confused how the break statements help with the code. Particularly, I'm confused why the first 'break' is needed when there is already an 'else'.
The second break confuses me as well.
I understand that 'break' statements stop a loop and go onto the next loop.
My interpretation of the code so is 'if the number does not equal to 6 then total = total + num, if it does equal 6 then the loop is broken and if it is broken, add changes to False'.
I'm not sure if that interpretation is correct or not.
I was wondering how seasoned Python coders interpret 'breaks' vs 'else'.
break will exit whatever loop the statement is in. It's useful for many things, but often it's used to "short-circuit" the loop. If we know that the rest of the loop is irrelevant after some condition is met, then it's just wasted resources to keep looping through.
The break statement allow you to leave the while loop, but the if else statement allow you to stay in loop, until the condition of the while loop change or a break statement is in the action into the while loop
The solution you've provided is extremely convoluted and hard to understand.
A much better solution is:
total = 0
for num in arr_2:
if(num >= 6 and num <=9):
continue
total += num
Or a more pythonic way:
filtered_arr = filter(lambda x: x <6 or x > 9, arr_2)
total = reduce(lambda x, y: x + y, arr)
Anyways, in your solution, the first break is absolutely redundant. The reason why there is a break there, is because when you've found a number that doesn't equal 6, you add it, and you get out of the while loop.
In other words, the solution should have used an if statement, instead of the while statement. The break is there to basically have the while loop execute once.
Because, if a number does equal 6, then add will be false, and the while loop will terminate. If a number does not equal 6, you get out of the while loop. So the while loop is pointless, and meant to be an if statement instead.
This is a tricky way to handle program flow with a toggle nested in conditional loops.
It's a little hard to follow, but it is a well-known classic pattern.
Initially ADD == True, so if we start with a number that is not 6 (as in your example), the algorithm adds the number & breaks out of the first while loop. When it breaks, the next statement executed will be the line while add == False
At this point ADD == TRUE so the second while loop will not be entered. The next statement executed will be for num in arr (the outermost loop).
The outer FOR loop will go again and this process will repeat.
When you encounter a 6, the number will not be added and the break will not occur. The program will execute the else clause, setting ADD = FALSE.
After the else clause, execution continues with statement while add == false. Since ADD == FALSE at this point, the second while loop will be entered.
From now on ADD will be FALSE so the first While loop will not be entered and numbers will not be added. Instead, the condition for the second while loop will be evaluated for each number. As long as numbers are not equal to 9, the second while loop will not be entered.
When you encounter a 9, you will enter the second while loop, switch ADD back to TRUE, and break out of the while loop.
The first 9 comes after a 6 (ADD is FALSE) so it just toggles ADD from FALSE to TRUE and the number 9 doesn't get added.
When the NEXT 9 is encountered, ADD is TRUE and the number is not 6, so the first while loop will be entered and the number 9 will get added.
This is a classic pattern that used to be used in assembly language code perhaps 40 years ago. As written, the IF statements toggle a state variable. The state variable is turned on when the start condition is met, and turned off when a stop condition is met. The while loops ensure that the toggle can only be turned ON when it was OFF and vice versa, and provide places to put in different handling when the state is ON vs when it is OFF. This pattern brings certain efficiencies that are completely irrelevant in modern high-level languages.
There are better ways to do this in all modern languages, but as an exercise in following tricky program flow it's quite good :)

Decrement the Variable I'm Incrementing in for loop

kind of a newbie to Python and I've looked around a bit but haven't found a satisfying answer to my question. I'm doing some practice problems and I want to make a method that gets rid of duplicate values in a list. So far, this is my code:
def noDouble(nums):
for x in xrange(len(nums) - 2):
if nums[x] == nums[x + 1]:
nums.pop(x)
x -= 1
return nums
What I want to happen is that if there's a duplicate, pop off one of the duplicates and then move back again (so that if there are, say, 3 instances of the same number, it'll get rid of al of them by 'rewinding').
I'm looking for an explanation for why my code doesn't work as well as an explained solution and I'd really appreciate any and all help. Thanks.
Because for doesn't count numbers; it iterates over a sequence. Every time the body of the loop executes, x is set to the next value produced by the xrange. The for statement couldn't care less what x is at the end of the loop.
You really shouldn't modify a list within a loop over it, anyway. The easier way to do this is to build a new list:
def remove_doubles(old):
new = []
for item in old:
if new and item == new[-1]:
continue
new.append(item)
return new
Of course, the really easy way to remove duplicates is list(set(foo)). But that will remove all duplicates, not just adjacent ones, and probably destroy the item order too.
As far as I understand it, the for loop isn't a simple increment like it is in C or Java; Python will actually force x back to the value it's expected to be for the next loop iteration. So decrementing x won't have the effect of adding more loop iterations, because it will be forcibly reset.
for x in range(10):
x -= 1
print x
will yield
-1
0
1
2
3
4
5
6
7
8
EDIT: here's a possibility for what you're trying to do, though the accepted answer is easier for your specific use case. Use while instead of for:
limit = len(nums) - 1
x = 0
while x < limit:
if nums[x] == nums[x+1]:
nums.pop(x)
x -= 1
x += 1
return nums
Though this code may still fail with an IndexError because of how you're accessing list elements. But still, that's how you'd add extra iterations.
Generally you never want to manipulate the counter in a loop (aside from setting it to break out of the loop). For a similar reason, you don't want to saw a branch you are sitting on, when cutting down a tree :-)
The safer route (compared to nested loops) is to build a set of operations in one loop, then pass this set to a second loop (each loop one level deep).

Python IndexError : string index out of range in substring program

I am writing a code for a class that wants me to make a code to check the substring in a string using nested loops.
Basically my teacher wants to prove how the function 'in', as in:
ana in banana will return True.
The goal of the program is to make a function of 2 parameters,
substring(subStr,fullStr)
that will print out a sentence saying if subStr is a substring of fullStr, my program is as follows:
def substring(subStr,fullStr):
tracker=""
for i in (0,(len(fullStr)-1)):
for j in (0,(len(subStr)-1)):
if fullStr[i]==subStr[j]:
tracker=tracker+subStr[j]
i+=1
if i==(len(fullStr)-1):
break
if tracker==subStr:
print "Yes",subStr,"is a substring of",fullStr
When i called the function in the interpreter 'substring("ana","banana")', it printed out a traceback error on line 5 saying string index out of range:
if fullStr[i]==subStr[j]:
I'm banging my head trying to find the error. Any help would be appreciated
There are a few separate issues.
You are not reseting tracker in every iteration of the outer loop. This means that the leftovers from previous iterations contaminate later iterations.
You are not using range, and are instead looping over a tuple of just the 0 and the length of each string.
You are trying to increment the outer counter and skipping checks for the iteration of the outer loop.
You are not doing the bounds check correctly before trying to index into the outer string.
Here is a corrected version.
def substring(subStr,fullStr):
for i in range(0,(len(fullStr))):
tracker=""
for j in range(0,(len(subStr))):
if i + j >= len(fullStr):
break
if fullStr[i+j]==subStr[j]:
tracker=tracker+subStr[j]
if tracker==subStr:
print "Yes",subStr,"is a substring of",fullStr
return
substring("ana", "banana")
First off, your loops should be
for i in xrange(0,(len(fullStr))):
for example. i in (0, len(fullStr)-1) will have i take on the value of 0 the first time around, then take on len(fullStr)-1 the second time. I assume by your algorithm you want it to take on the intermediate values as well.
Now as for the error, consider i on the very last pass of the for loop. i is going to be equal to len(fullStr)-1. Now when we execute i+=1, i is now equal to len(fullStr). This does not fufill the condition of i==len(fullStr)-1, so we do not break, we loop, and we crash. It would be better if you either made it if i>=len(fullStr)-1 or checked for i==len(fullStr)-1 before your if fullStr[i]==subStr[j]: statement.
Lastly, though not related to the question specifically, you do not reset tracker each time you stop checking a certain match. You should place tracker = "" after the for i in xrange(0,(len(fullStr))): line. You also do not check if tracker is correct after looping through the list starting at i, nor do you break from the loop when you get a mismatch(instead continuing and possibly picking up more letters that match, but not consecutively.)
Here is a fully corrected version:
def substring(subStr,fullStr):
for i in xrange(0,(len(fullStr))):
tracker="" #this is going to contain the consecutive matches we find
for j in xrange(0,(len(subStr))):
if i==(len(fullStr)): #end of i; no match.
break
if fullStr[i]==subStr[j]: #okay, looks promising, check the next letter to see if it is a match,
tracker=tracker+subStr[j]
i+=1
else: #found a mismatch, leave inner loop and check what we have so far.
break
if tracker==subStr:
print "Yes",subStr,"is a substring of",fullStr
return #we already know it is a substring, so we don't need to check the rest

Python Program, while loop not executing?

Names=[0,1,2,3,4]
Names[1]=='Ben'
Names[2]=='Thor'
Names[3]=='Zoe'
Names[4]=='Katie'
Max=4
Current=1
Found=False
PlayerName=input('What player are you looking for?')
while Found==False and Current==Max:
if Names[Current]==PlayerName:
Found=True
else:
Current+=1
if Found==True:
print('Yes, they have a top score')
else:
print('No, they do not have a top score')
This is the program. When any of the 4 names at the top are entered, the program should print, 'Yes, they have a top score', but when anything else is entered it should print,'No, they do not have a top score'.
However whatever name is entered it returns the 'No, they do not have a top score' message. I think it may have something to do with the loop but not sure what.
Your second condition is inverted. You want
while Found==False and Current!=Max:
That said, in Python you can do this much more simply using the in operator:
names = ['Ben', 'Thor', 'Zoe', 'Katie']
player_name = input('What player are you looking for?')
if player_name in names:
print('Yes, they have a top score')
else:
print('No, they do not have a top score')
That way, you don't need the while loop at all.
Names[1]=='Ben'
...
Is not assignment, it is equality check (and it returns False, although this is irrelevant)
Hence, your list is not modified, and names are checked against the list [0,1,2,3,4], and they never match, which is not a surprise.
Additionally, your loop condition is incorrect, and the code there is never run.
You should however consider writing your program is a more pythonic way, using the in operator, as suggested above, or a least using a for loop, iterating over your list.
In your while loop, you're doing these comparisons:
Found==False and Current==Max
The second part of the condition will never evaluate to True because Current is always set to 1 before the loop, which is != to Max - therefore, the code in the loop never evaluates.
Look here:
Names=[0,1,2,3,4]
Names[1]=='Ben'
Names[2]=='Thor'
Names[3]=='Zoe'
Names[4]=='Katie'
This doesn't do what you think it does. Afterwards, Names is equal to [0, 1, 2, 3, 4]. The next few lines don't assign names to Names but only check whether an element is equal to a name. For example, Names[1]=='Ben' checks if the second element in Names is equal to Ben (so this evaluates to True or False) but nothing is done with the result.
Your code never enters inside while loop, because initially Current = 1 and Max = 4, so they are not equal.
Do you try to program BASIC in Python? :-)
Others have answered why it does not work. Even if you do these changes, your program does look more like BASIC than like Python.
You should do the following:
Use index 0 as well. You allocate 0..4 and use 1..4. Just use 0..3.
iterate through a list with for item in listobject: instead of the while loop.
Don't do if Found==True:, just use if Found:
Don't name your variables with starting uppercase - these names are for classes. Use found instead of Found.

Categories

Resources