Can I combine a `while` and a `for` loop?

This is my inelegant solution:

def over_nine_thousand(lst):
  i = 0
  if len(lst) == 0:
    return 0
  elif sum(lst) < 9000:
    return sum(lst)
  while i <= 9000:
    for value in lst:
      if i > 9000:
        break
      i += value
    return i

I thought abount break only after having seen the ‘hint’ section. But there’s a thing I really don’get: if I use a while loop which sets the condition < 9000, shouldn’t it stop automatically as soon as the condition gets False (i.e. when ‘i’ reaches a value higher than 9000)?

Hi, @crazybeetle
To answer your question, yes, the while loop will terminate when i is greater than or equal to 9000, but only if while knows that this is the case. The way while works, it makes that comparison only when the while line is executed, each time the loop completes; it does not somehow keep track of things going on in the body of the loop.

The problem here is that you are mixing a for loop with a while loop unnecessarily; the while condition is evaluated one time, but never again!

while value_condition:
    for something in a_list:
        if value_condition:
            break
        increment value
    return value

The for loop does all the work, and when the job is done, returns the value. When return is reached, the function terminates. Control is never again passed to while. You can simply omit while, and it still works.

Use one or the other:

index = 0
while value_condition and not index >= list_length:
    use index to get next list element
    increment value 
    increment index
return value

– or –

for something in a_list:
    increment value
    if value_condition:
        break
return value    

(You don’t actually need break, just return value.)

1 Like

Thank you very much. Now I can see my mistake.
This was very helpful because, to be honest, I find loops quite challenging.
During the lessons everything seems to proceed smoothly. But as soon as I face a non-standard exercise things get harder :grimacing:
I think that the hardest part of knowing how to code is understanding how methos REALLY work in the “backstage”.
But hey, I won’t give up. Thanks again :+1:

2 Likes

Hello! I was wondering why we use a “for” loop in this and not a “while” loop. To me it seems more straightforward to say “while number < 9000…” but maybe there is something I am missing? I also got the correct answer with a while loop but it didn’t accept my code as a “solution” so I feel like maybe there is a consequence to using the while loop that I hadn’t thought of. Thanks!

2 Likes

Hi, I used a while loop and had my code accepted just fine. But I did notice that it didn’t accept my code until the functions would return a list with a sum less than 9000 and return 0 if the list was empty to start with.

2 Likes
def over_nine_thousand(lst):
  lst_sum = 0
  if len(lst) != 0:
    while True:
      for i in lst:
        lst_sum = lst_sum + i
        if lst_sum > 9000:
          break
      return lst_sum
  return lst_sum
    
1 Like

You can remove your while-loop because it only does one iteration and is therefore the same as no loop at all.
And then you can remove your first if-statement too (empty list is not a special case)

1 Like

Hi,

I ended up with this solution, that was accepted:

def over_nine_thousand(lst):
power = 0
for i in lst:
while power < 9000:
power += i
break
return power

How can we solve using only for loop?~
Thanks

1 Like

That won’t run because it’s missing indentation which is part of the information that needs to exist in your code.
It looks like you have a completely unconditional break, and if so then one of your loops isn’t a loop at all because it’ll only run at most once. (That also makes me question if it’s doing the right thing overall)

2 Likes

Hello ionatan,

Sorry, when i pasted the code in the forum message, all indentation was lost :slightly_smiling_face:
Here’s the code with the correct indentation:

def over_nine_thousand(lst):
  power = 0
  for i in lst:
    while power < 9000:
      power += i
    break
  return power

I used the break to stop the while loop as soon as the power variable gets over the 9000 thresold.
Oddly as it may seem, this solution was accepted by the editor and allowed me to move to the next lesson.

I also tried lots of different inputs and always got the expected output.

1 Like

Almost all forums have formatting tools, code should not be reformatted, so for that purpose one of the buttons in the post editor is for escaping those formatting rules.

A loop that executes once isn’t a loop. If your break is inside the while loop then that’s not a while loop it’s an if-statement. Did you know it only executes once? You need to be a bit more deliberate about your code because you’re the one who says what should happen.
If the break is in the for-loop, then only the first element in the list would get considered.

See how it’s very weird either way?

And, because you don’t actually use break (it’s just an if-statement), you changed the behaviour. That lets me construct some input where it fails - your loop won’t stop early (break), so if I give it an infinite series of numbers then your loop won’t ever stop:

from itertools import cycle

over_nine_thousand(cycle([1]))

cycle does exactly what its name suggests. It repeats values in an infinite cycle, so the input here is
[1,1,1,1,1,1, ...]
What the function should be doing is adding those 1’s up until it reaches 9001, at which point it should stop the loop and return the result.

1 Like

Hi again ionatan,

I understand your logic, and I replaced the while loop with an if statement and it works the same way :slight_smile:
Thank you for your time and for your tips. I actually edited my last post in order to represent the identation of the code :smiley:

1 Like

Ahh I hope your current code isn’t what’s in your post above, because that will only look at the first value.
(now the for-loop isn’t a loop instead)

Oh and your condition less than 9000 doesn’t match the instructions!

until the sum is greater than 9000

(you’re off by one, 9000 is not greater than 9000, but it causes your condition to evaluate to false)

Also, here’s an alternative which has the stopping condition in the loop header instead of using break:

def over_nine_thousand(numbers):
    numbers = iter(numbers)
    power = 0
    while power <= 9000:
        power += next(numbers)
    return power

iter returns an iterator which is a value which can be repeatedly asked for next value

…there’s a problem with that though, what if there aren’t enough numbers to exceed 9000? I suppose one might just say that’s undefined and it’s the caller’s fault if that happens.

1 Like

There you go mate :slight_smile:

def over_nine_thousand(lst):
sum = 0
for i in lst:
sum+=i
if sum>=9000:
break
return sum

2 Likes

i’ve tried to do the following:

def over_nine_thousand(lst):
  summ = 0
  while summ<9000:
    for item in lst:  
      summ+=item
  return summ
#Uncomment the line below when your function is done
print(over_nine_thousand([8000, 900, 120, 5000]))

BUT, it’s doing one more iteration after it reaches 9020(the expected value) and returns 14020 for some reason…

1 Like

It doesn’t do one more iteration. It iterates through all of it.

Can you argue for why each line is required there?
Have you thought about what actions a loop carry out? If you place your finger at a first value in a list, then you’ll move it one step repeatedly until you reach the end.
Is it enough to do one such loop for this task? If you were to manually carry it out, you’d move your finger down the list, and then stop once the value is over 9000. That sounds like one loop to me. What is your other loop doing?

Like several other people, your stop condition is also wrong, it’ll stop too early. The function’s name is OVER 9000, reaching 9000 is not when you should stop, it needs to be bigger than that.

2 Likes

I’ve figured it out, my code logic was a bit wrong, i didn’t escape the loop “in the correct moment” hence i was getting that extra iteration…
here is my new code:

def over_nine_thousand(lst):
  summ = 0
  for item in lst:
    summ += item
    if summ>9000:
      return summ
  if summ<9000:
    return summ
  elif lst==0:
    return 0

so yeah, my if statement/while loop should check after the addition process not before it(as in my previous code)

1 Like

Is the list a number? You’re comparing it to 0 >_<
Should there really be two comparisons to 9000?
Does your function return anything at all when the sum is 9000?

2 Likes

my bad for some reason i put a 0 instead of an empty list ‘’, and for the two comparisons to 9000 the first one is incase the sum exceeds 9000, the second one if the sum doesn’t reach 9000.

def over_nine_thousand(lst):
  summ = 0
  for item in lst:
    summ += item
    if summ>9000:
      return summ
  if summ<=9000:
    return summ
  elif lst==[]:
    return 0
print(over_nine_thousand([8000, 900, 120, 5000]))

1 Like