How can I iterate over a list backward?


#1

Question

In the context of this code challenge, how can I iterate over a list backward?

Answer

There are a few ways that you can iterate over a list backward.

One way is by utilizing the range() method, with a negative step value, so that the index decreases by 1 per element, essentially going backward in the list. The start index must begin at the last index of the list, and the end index would have to be offset by 1 to the first index, because it is exclusive. This will look something like the following,

for i in range(len(list)-1, -1, -1):
  ...

Another way to iterate over a list backward is to utilize list slicing, with a negative step. This will return a new list of elements in reverse order.

for i in list[::-1]:
  ...

#2

Extra Study

Consider the classic game of the distant past, Reversii where we are given a random list of numbers and have to put them in order using only flips from the right hand side. We won’t get into that level of difficulty, yet, but we can flip the entire list as a starting point. Let’s take a list of 10 items and flip it…

>>> x = list(range(10))
>>> a, b = x[0], x[-1]
>>> x[0], x[-1] = b, a
>>> x
[9, 1, 2, 3, 4, 5, 6, 7, 8, 0]
>>> a, b = x[1], x[-2]
>>> x[1], x[-2] = b, a
>>> x
[9, 8, 2, 3, 4, 5, 6, 7, 1, 0]
>>> a, b = x[2], x[-3]
>>> x[2], x[-3] = b, a
>>> x
[9, 8, 7, 3, 4, 5, 6, 2, 1, 0]
>>> a, b = x[3], x[-4]
>>> x[3], x[-4] = b, a
>>> x
[9, 8, 7, 6, 4, 5, 3, 2, 1, 0]
>>> a, b = x[4], x[-5]
>>> x[4], x[-5] = b, a
>>> x
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Now let’s take a list of 9 items and flip it…

>>> x = list(range(1, 10))
>>> a, b = x[0], x[-1]
>>> x[0], x[-1] = b, a
>>> x
[9, 2, 3, 4, 5, 6, 7, 8, 1]
>>> a, b = x[1], x[-2]
>>> x[1], x[-2] = b, a
>>> x
[9, 8, 3, 4, 5, 6, 7, 2, 1]
>>> a, b = x[2], x[-3]
>>> x[2], x[-3] = b, a
>>> x
[9, 8, 7, 4, 5, 6, 3, 2, 1]
>>> a, b = x[3], x[-4]
>>> x[3], x[-4] = b, a
>>> x
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> 

See any pattern there? This is suggestive of an algorithm. All we need is to understand a breaking condition to set it in motion. Note the condition on while below…

>>> x = list(range(10))
>>> i = 0
>>> while i + 1 <= len(x) // 2:
	a, b = x[i], x[-(i+1)]
	x[i], x[-(i+1)] = b, a
	i += 1

	
>>> x
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> x = list(range(1, 10))
>>> i = 0
>>> while i + 1 <= len(x) // 2:
	a, b = x[i], x[-(i+1)]
	x[i], x[-(i+1)] = b, a
	i += 1

	
>>> x
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> 

Any hint as to how we would use i in the Reversii plot?

As noted, this is for extra study when one has competed the course. Bookmark it and return later to explore this concept. It won’t come up in the course but will surely have piqued your interest. See you on the flip-flop.


We can intuit this into a utility function now that we have the mechanics and contraints we need…

>>> def reverse(x, i=0):
    while i + 1 <= len(x) // 2:
        a, b = x[i], x[-(i+1)]
        x[i], x[-(i+1)] = b, a
        i += 1
    return x

>>> reverse(list(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> reverse(list(range(1, 10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> 

Just to note, we’re close, but this is not Reversii.


Extra Study, piled on…

To make our function less vulnerable to stray inputs…

>>> def reverse(x, i=0):
  try:
    while i + 1 <= len(x) // 2:
        x[-i - 1], x[i] = x[i], x[-i - 1]
        i += 1
    return x
  except:
    return x
>>> reverse('a string')
'a string'
>>> reverse(1)
1
>>> reverse({'one': 1})
{'one': 1}
>>> reverse(list(range(1, 10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> reverse(list(range(10)))
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> 

What’s more we can deal with one exception, a str parameter…

>>> def reverse(x, i=0):
  try:
    while i + 1 <= len(x) // 2:
      x[-i - 1], x[i] = x[i], x[-i - 1]
      i += 1
    return x
  except:
    if isinstance(x, str):
      return ''.join(reverse(list(x)))
    else:
      return x

>>> reverse('a string')
'gnirts a'
>>>