How to Reverse Python Lists | In-place, slicing & reversed()

How to Reverse Python Lists | In-place, slicing & reversed()

Kundan date_range May 18, 2020 local_offer

Python lists can be reversed using built-in methods reverse(), reversed() or by [::-1] list slicing technique. The reverse() built-in method reverses the list in place while the slicing technique creates a copy of the original list. The reversed() method simply returns a list iterator that returns elements in reverse order.

Below are the three built-in, common method used for reversing Python lists.

1. Reversing lists in-place using reverse()

Bash
1
2
3
4
5
6
>>> nums = [1,2,3,4,5,6,7,8]
>>> type(nums.reverse())
<type 'NoneType'>
>>> nums
[8, 7, 6, 5, 4, 3, 2, 1]
>>>

2. Reversing lists using slicing (creates a new copy)

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>> nums = [1,2,3,4,5,6,7,8]
>>>
>>> nums_reversed = nums[::-1]
>>> nums_reversed
[8, 7, 6, 5, 4, 3, 2, 1]
>>> type(nums_reversed)
<type 'list'>
>>>
>>> nums
[1, 2, 3, 4, 5, 6, 7, 8]
>>>

3. Reversing lists using reversed

Bash
1
2
3
4
5
6
7
>>> nums = [1,2,3,4,5,6,7,8]
>>> reversed(nums)
<listreverseiterator object at 0x10fced990>
>>>
>>> [n for n in reversed(nums)]
[8, 7, 6, 5, 4, 3, 2, 1]
>>>

Let us look at each in detail to understand pros, cons and when to use a particular method.

Bash
1
2
3
4
5
6
>>> nums = [1,2,3,4,5,6,7,8]
>>> type(nums.reverse())
<type 'NoneType'>
>>> nums
[8, 7, 6, 5, 4, 3, 2, 1]
>>>

Time and Space Complexity of Python List reverse()

The reverse() method works in O(n) time complexity and with O(1) space. Internally, when reverse() is called it operates by swapping i-th element with (n-i)th element. Therefore, the first element is replaced with the last element, the second element is replaced with the second last element and so on. Thus, a total of N/2 swap operations are required for list reversal. That makes the overall time complexity as O(N/2) which is same as O(N)

Pros of reverse methods:

  • In-Place
  • Intuitive and easy to understand, it upholds code readability.

Cons of reverse() method:

  • The order of elements in the original list is changed.

When to use reverse() methods ?

Scenarios where order of elements in the original list can be altered and keeping a low memory footprint is desired .

Python lists can be reversed using the [::-1] slicing suffix. It creates and returns a new copy of the list without altering the actual list.

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
>>> nums = [1,2,3,4,5,6,7,8]
>>>
>>> nums_reversed = nums[::-1]
>>> nums_reversed
[8, 7, 6, 5, 4, 3, 2, 1]
>>> type(nums_reversed)
<type 'list'>
>>>
>>> nums
[1, 2, 3, 4, 5, 6, 7, 8]
>>>

What does [::-1] notation mean? It means to select elements starting from the first element till the last element with a stride of negative one, i.e, in reverse order. The list slicing notation is [start:end:step], so here start=end=None means the defaults (0 and n-1) and step=-1 implies reverse order.

What are the pros, cons of using slicing for list reversal, and when should we prefer slicing over reverse() or reversed() ?

Pros of list slicing for list reversal:

  • The original list is not altered. The order of elements in the original arrays is maintained before and after the slicing operation.

Cons:

  • Takes extra space by creating a list of the same size.
  • While [::-1] notation is shorter, it is cryptic and requires more attention to understand as compared to english words syntax reverse() or reversed(). In short not the best for code readability.

When to use slicing or Python List Reversal:

  • If it is a requirement to preserve the order of elements in the original list.
  • It is fine to allocate extra memory for the copy of the list.

Using reversed() for Python list reversal

Python lists can also be reversed using the built-in reversed() method. The reversed() method neither reverses the list in-place nor it creates a copy of the full list. It instead returns a list iterator(listreverseiterator) that generates elements of the list in reverse order.

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
>>> nums = [1,2,3,4,5,6,7,8]
>>> reversed(nums)
<listreverseiterator object at 0x10fced990>
>>>
>>> [n for n in reversed(nums)]
[8, 7, 6, 5, 4, 3, 2, 1]
>>>
>>>
>>> def reverse_python_list(nums):
...         for num in reversed(nums):
...             yield num
...
>>>
>>> list(reverse_python_list([1,2,3,4,5,6,7,8]))
[8, 7, 6, 5, 4, 3, 2, 1]
>>>

Note that calling reversed(nums) simply returns an iterator object. We can see in the following example that the reverse_python_list method, which simply wraps the reversed() method, does not modify the original list or create a copy of the list.

Pros of reversed() for list reversal:

  • No extra space is required
  • The original list remains unchanged
  • The syntax aids to code readability

Cons:

  • None really. Just that extra caution needs to be exercised with iterators.The returned iterator can be used only once(it gets exhausted on looping over once). So, if it is required to access the reversed list multiple times, we need to create a copy of the list or call the reversed() function multiple times.

Common List Reversal Problems

Let us take a look at a few other common Python Lists reversal related problems.

How to reverse a list in python using for loop ?

To reverse a list of size n using for loop, iterate on the list from (n-1)th element to the first element and yield each element.

Bash
1
2
3
4
5
6
7
8
9
>>> def reverse_list_using_for(nums):
...     # Traverse [n-1, -1) , in the opposite direction.
...     for i in range(len(nums)-1, -1, -1):
...         yield nums[i]
...
>>>
>>> print list(reverse_list_using_for([1,2,3,4,5,6,7]))
[7, 6, 5, 4, 3, 2, 1]
>>>

How to reverse python list using recursion ?

To reverse a list of using recursion, we define a method that returns sum of two lists, the first being the last element (selected by -1 index) and the second one being reverse of the entire list upto the last element (selected by :-1). The base condition is met when all the elements are exhausted and the array is empty, upon which we return an empty array. Below is the functional code.

Bash
1
2
3
4
5
6
7
8
9
>>> def reverse_list_using_recursion(nums):
...     if not nums:
...         return []
...     return [nums[-1]] + reverse_list_using_recursion(nums[:-1])
...
>>>
>>> print reverse_list_using_recursion([1,2,3,4,5,6,7])
[7, 6, 5, 4, 3, 2, 1]
>>>

How to reverse part(subset or slice) of Python list?

To reverse a part of a list, the built-in reverse, reversed or slicing methods can be used on the subset identified by slicing. The following code shows all the three approaches:

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
>>> nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>>
# Method: 1 Using Slicing
>>> nums[3:8][::-1]
[8, 7, 6, 5, 4]
>>>
>>>
# Method: 2 Using reverse()
>>> nums_subset = nums[3:8]
>>> nums_subset.reverse()
>>> nums_subet
[8, 7, 6, 5, 4]
>>>
>>>
# Method: 3 Using reversed()
>>> list(reversed(nums[3:8]))
[8, 7, 6, 5, 4]
>>>

How to reverse Python Numpy Array?

The numpy arrays can be reversed using the slicing technique (using [::-1] slice descriptor) or by using numpy’s flipud method. The following code shows the usage of both:

Bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
>>> np_array = np.array([1, 2, 3, 4, 5, 6])
>>>
# Method 1: Using slicing 
>>> np_array[::-1]
array([6, 5, 4, 3, 2, 1])
>>> type(np_array[::-1])
<type 'numpy.ndarray'>
>>>
>>>
# Method 1: Using flipud
>>> np.flipud(np_array)
array([6, 5, 4, 3, 2, 1])
>>> type(np.flipud(np_array))
<type 'numpy.ndarray'>
>>>

Summary

In this tutorial we learnt the three techniques for Python list reversal, viz reverse(), reversed() and slicing. We also looked at the pros and cons of each method.

So, which is the best way to reverse list in python?

The answer depends on the requirements. If the requirement is to maintain the order of original elements then reversed() or slicing technique should be used. If the requirement is to have minimal memory footprint, reverse() or reversed() are more suited. If it is required to have a minimal memory footprint along with maintaining order of elements in the original list, reversed() should be used. In general, if there is no such preference, reverse() or reversed() can be preferred over slicing technique as it aids to code readability.