Loop Intuition

Hello! I am just learning loops in python, but I am having a hard time building an intuition for (1) when to use which type of loop (i.e for vs while loops), (2) when to consider nesting loops, and (3) when using a loop might be more appropriate than just an if statement.
For instance, I initially thought to use an if statement to generate a function that would return a given list with the even elements removed:

However, the solution used a while loop:

!

I am unclear about the logic behind the reason for using a while loop over an if statement…would anyone explain and possibly suggest some tips for developing an intuition for knowing when to use loops, what types, and when to nest them? Thanks!

The type of loop, hmmm, that is the question. At first it is tricky to decide. What do we want from the loop? What objects are in play? Are we iterating an object or performing an action within a conditional environment?

1 Like

In the examples you provided there are different outcomes.
With the IF statement version you ONLY check the first element to see if it is even or odd.
With the WHILE loop you check the first element of the lst-variable continuously and remove all elements that are even from the beginning of the list.
Consider this scenario:
lst = [2,2,4,5,2]
with the IF version you return [2,4,5,2] #(only first even element removed)
but with the WHILE version you return [5,2] #(3 even elements removed)

This is also a good illustration of a use-case for a while loop instead of a for loop, because you do not know upfront when the loop could be terminated on a for loop.
You could do:

for i in range(len(lst)):
  if lst[i] % 2 != 0: # if we find an uneven number
    return lst[i:] # break the loop (and function) by returning the correct result
return [] # if the lst only contains even numbers, we return an empty list

This is actually slightly more optimized because you do not modify the original list at all (and lists are passed by reference, don’t worry about that if you are still learning)

When to use while versus for is a combination of taste and intuition. But it is my personal experience that while loops are better suited if you do not know the number of iterations, or when you want to modify the iterator itself.
Most of the times I use for loops (for i in range, for i in xs) when I want to loop over something that I do not modify.

A while loop would be good for things that start out as possibly infinite loops. As an example: the collatz-conjecture.
This conjecture states that any positive integer would converge to 1 if you follow the rule "if it is even the next term is half of the current term, if it is odd the next term is 3 times the current term plus one.

Say you want to count how many iterations it takes:

def collatz(n):
  counter = 0
  while n != 1:
    if n % 2 == 0: n //= 2
    else: n = (n * 3) + 1
    counter += 1
    if counter > 1000000: return"timeout" # security to avoid being stuck
  print "it took {} times".format(counter)

This would be ‘difficult’ to achieve with a for loop

Then for your question regarding nesting loops.
I advise to try to avoid nesting loops where possible, for your running time will go through the roof for any decent input size.
Even when it is unavoidable to use nested loops, I would consider it good practice to break up your function into two separate functions

DISCLAIMER: I have not run the code provided before posting it, it is just illustrative

Hope this helps,

-kh

One more thing to add.
Modifying a passed list is usually not a good idea (because in contrast to a singleton variable, you actually modify the list itself).
But you can circumvent it, and not use a for or while loop at all, but use recursion. This way you still have the downside of multiple lists being created, but the original list stays intact.
It is ‘sort-of’ functional programming with tail recursion.

def remove_starting_evens(lst):
  return lst if len(lst) == 0 or lst[0] % 2 != 0 else remove_starting_evens(lst[1:])

For beginner/novice programmer it can look somewhat mind-boggling, but it is a paradigm that is used a lot.
What happens is you have a ternary operator (sort of a short cut on a if-else statement. It checks for the empty list or for the first element being even, and if so, returns the input, and else returns a new call to the same function with a list that is one element shorter.

Fantastic! Thank you so much for this thoughtful and valuable reply - I have learned a lot!

1 Like