Skip to main content

How to Shift and Rotate Lists in Python

Shifting (or rotating) a list involves moving elements to the beginning or end, wrapping them around as if the list were circular.

This guide explores various methods for shifting lists in Python, including list slicing, append() and pop(), the collections.deque class, and numpy.roll().

List slicing provides a concise and efficient way to shift lists without modifying the original list. This is generally the best approach for most cases.

Shifting Left (Rotate Left)

To shift a list to the left (move the first element to the end):

a_list = [1, 2, 3, 4, 5]
new_list = a_list[1:] + a_list[:1]
print(new_list) # Output: [2, 3, 4, 5, 1]
  • a_list[1:]: This slice creates a new list containing all elements from index 1 (the second element) to the end.
  • a_list[:1]: This slice creates a new list containing only the element at index 0 (the first element).
  • +: The + operator, when used with lists, concatenates them.

Shifting Right (Rotate Right)

To shift a list to the right (move the last element to the beginning):

a_list = [1, 2, 3, 4, 5]
new_list = a_list[-1:] + a_list[:-1]
print(new_list) # Output: [5, 1, 2, 3, 4]
  • a_list[-1:] creates a list containing only the element at the last index.
  • a_list[:-1] creates a list containing all elements up to the last index.

Generalized Shift Function

Create a function to shift by an arbitrary amount, either left or right. Positive index values shift right, negative values shift left:

def shift_list(lst, index=1):
index = index % len(lst) # Handle shifts larger than list length
return lst[index:] + lst[:index]

a_list = [1, 2, 3, 4, 5]

print(shift_list(a_list, 1)) # Output: [2, 3, 4, 5, 1]
print(shift_list(a_list)) # Output: [2, 3, 4, 5, 1] (default shift = 1)
print(shift_list(a_list, 2)) # Output: [3, 4, 5, 1, 2]
print(shift_list(a_list, -1)) # Output: [5, 1, 2, 3, 4] (shift left)
print(shift_list(a_list, 8)) # Output: [4, 5, 1, 2, 3] (8 % 5 = 3)
  • index = index % len(lst): The modulo operator (%) ensures that the shift amount is always within the valid range of list indices. This handles cases where index is larger than the list length or negative.
  • The rest of the function uses the same slicing logic as before.

Shifting with append() and pop()

While less efficient than slicing, you can shift using append() and pop():

# Move the first list item to the back
a_list = [1, 2, 3, 4, 5]
a_list.append(a_list.pop(0))
print(a_list) # Output: [2, 3, 4, 5, 1]

# Move the last list item to the front
a_list = [1, 2, 3, 4, 5]
a_list.insert(0, a_list.pop())
print(a_list) # Output: [5, 1, 2, 3, 4]
  • Using pop() and append() modifies the list in place, while slicing creates a new list.
  • a_list.pop(0) removes and returns the element at the first index (index 0)
  • The value returned by pop(0) is then added to the end of the list using a_list.append().
  • To move multiple items, you can use a for loop, but that is less readable.

Shifting with collections.deque

The collections.deque class (double-ended queue) is specifically designed for efficient appends and pops from both ends. It has a built-in rotate() method that's ideal for shifting:

from collections import deque

deq = deque([1, 2, 3, 4, 5])

deq.rotate(1) # Rotate right by 1
print(deq) # Output: deque([5, 1, 2, 3, 4])

deq.rotate(-1) # Rotate left by 1
print(deq) # Output: deque([1, 2, 3, 4, 5])
  • deque.rotate(n): Rotates the deque n steps to the right (if n is positive) or left (if n is negative).
  • deque is generally much faster than using append() and pop() repeatedly on a standard Python list, especially for large lists and large shifts.

Shifting with numpy.roll() (for NumPy arrays)

If you're working with NumPy arrays (not standard Python lists), the numpy.roll() function is highly efficient:

import numpy as np

arr = np.array([1, 2, 3, 4, 5])

new_array = np.roll(arr, 1) # Shift right by 1
print(new_array) # Output: [5 1 2 3 4]

new_array = np.roll(arr, -1) # Shift left by 1
print(new_array) # Output: [2 3 4 5 1]
  • You can pass an array to np.roll() along with the integer number representing the number of places that you want to shift.