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 :)
Related
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.
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.
I'm taking a course on programming (I'm a complete beginner) and the current assignment is to create a Python script that sorts a list of numbers in ascending order without using built-in functions like "sorted".
The script I started to come up with is probably laughably convoluted and inefficient, but I'd like to try to make it work eventually. In other words, I don't want to just copy someone else's script that's better.
Also, as far as I can tell, this script (if it ever functioned) would probably just put things in a NEW order that wouldn't necessarily be ascending. This is just a start, though, and hopefully I'll fix that later.
Anyway, I've run in to several problems with the current incarnation, and the latest is that it just runs forever without printing anything.
So here it is (with hashes explaining what I was trying to accomplish). If someone could look over it and tell me why the code does not match my explanations of what each block is supposed to do, that would be great!
# The numbers to be inputted, could be anything
numList = [1, 25, 5, 6, 17, 4]
# The final (hopefully sorted) list
numSort = []
# The index
i = 0
# Run the loop until you run out of numbers
while len(numList) != 0:
# If there's only one value left in numList,
# attach it to the end of numSort.
# (Variable 'basket' is just for transporting numbers)
if len(numList) == 1:
basket = numList.pop()
numSort.append(basket)
# The rest of the elifs are supposed to compare values
# that sit next to each other.
# If there's still a number in numList after 'i'
# and 'i' is smaller than that next number
# then pop 'i' and attach it to the end of numSort
elif numList[i+1] != numList[-1] and numList[i] < numList[i+1]:
basket = numList.pop(i)
numSort.append(basket)
# If there's NOT a number after 'i'
# then compare 'i' to the first number in the list instead.
elif numList[i+1] == numList[-1] and numList[i] < numList[0]:
basket = numList.pop(i)
numSort.append(basket)
# If 'i' IS the last number in the list
# and has nothing to compare itself to,
# Then start over and go through it again
# from the beginning
elif numList [i+1] == numList[-1]:
i = 0
# If 'i' is not at the end of numList yet
# and 'i' is NOT smaller than the next number
# and there are still numbers left
# then move on to the next pair
# and continue comparing and moving numbers
else:
i = i+1
# Hopefully these will be in ascending order eventually.
print(numSort)
Here is a simple way to sort your list with a classic loop :
myList = [2,99,0,56,8,1]
for i,value in enumerate(myList):
for j,innerValue in enumerate(myList):
if value < innerValue: #for order desc use '>'
myList[j],myList[i]=myList[i],myList[j]
print(myList)
The Algorithm behind this code is :
fix one value of the list and compare it with the rest
if it is smallest then switch the index of two values
I hope this will help you
Your conditions are essentially:
If there is only one number in the list
The current number is less than the next, which is not equal to the last number
The current number is less than the first number, and the next number is equal to the last number
The next number is equal to the last number
If you trace out the code by hand you will see how in many cases, none of these will evaluate to true and your "else" will be executed and i will be incremented. Under these conditions, certain numbers will never be removed from your original list (none of your elifs will catch them), i will increment until the next number is equal to the last number, i will be reset to zero, repeat. You are stuck in an infinite loop. You will need to update your if-statement in such a way that all numbers will eventually be caught by a block other than your final elif.
On a separate note, you are potentially comparing a number to only one number in the current list before appending it to the "sorted" list. You will likely need to compare the number you want to add to your "sorted" list and find its proper place in THAT list rather than merely appending.
You should also consider finding the end of list using a method more like
if i == len(numList) - 1
This will compare the index to the length of the list rather than comparing more values in the list which are not necessarily relevant to the order you are trying to create.
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).
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.