Using the deque data structure

from collections import deque

#create a deque from an iterable
d = deque([1, 2, 3, 4, 5])

print(d)

#add element at the left end
d.appendleft(0)
print(d)

#add element at the right end
d.append(6)

print(d)

A queue is a data structure that follows a First-In-First-Out (FIFO) ordering for inserting and removing elements. A deque is a type of queue that also follows a Last-In-First-Out (LIFO) ordering for insertions and retrievals. The name "deque", pronounced as  "deck",  is short for "double-ended queue" and reflects the fact that elements can be added or removed from either end of the structure.

The collections module in the standard library implements the deque data structure. The implementation provides O(1) time complexity for appending and popping from both ends of the deque.

Instantiate deque objects

The most straightforward way to instantiate a deque object is to create an empty deque. To do so, you will need to import the collections module and use the deque constructor without any argument.

create an empty deque

from collections import deque 

queue = deque()

print(queue)

Another way to instantiate a deque is with an iterable object. This could be any type of sequence or collection such as a list, set,  tuple, range, etc. The deque constructor takes the iterable as an argument and creates a deque from the elements.   

create a deque from an iterable

from collections import deque 

# creating deque from list 
queue1 = deque(['Mon', 'Tue', 'Wed']) 

#Creating deque from tuple 
queue2 = deque(('Thur', 'Fri', 'Sat')) 

# Creating deque from range
queue3 = deque(range(10))

print(queue1)
print(queue2)
print(queue3)

Populate the deque

Populating the deque refers to adding elements to the deque at any of its ends after it has been created. This is accomplished using various methods  defined by the deque class.

Inserting single element to the deque

Single insertions are achieved primarily using two methods i.e append() and appendleft() methods. The append() method adds a single item to the right/back end of the deque.

append(item)

insert elements at the end of the deque

from collections import deque

d = deque()

d.append(0)
d.append(1)
d.append(2)
d.append(3)
d.append(4)
d.append(5)

print(d)

The appendleft() method adds a single item to the left/front end of the deque.

appendleft(item)

insert an item at the left side of the deque

from collections import deque

d = deque()

d.appendleft(0)
d.appendleft(1)
d.appendleft(2)
d.appendleft(3)
d.appendleft(4)
d.appendleft(5)

print(d)

Insert multiple elements at once

The deque also supports multiple element insertion through the extend() and extendleft() methods. The two methods takes in an iterable containing the elements to be inserted and inserts the at the respective ends. The extend() method inserts all the elements of the iterable at the right/back end of the deque, while the extendleft() method inserts all the elements of the iterable at the left/front end of the deque.

extend the deque at the right end

from collections import deque

d = deque([1, 2, 3, 4, 5])
print('before: ', d)

items = (6, 7, 8, 9)

#use the extend method
d.extend(items)

print('after: ', d)

 extend the deque at the left end

from collections import deque

d = deque([6, 7, 8, 9])
print('before: ', d)

items = (5, 4, 3, 2, 1, 0)

#use the extend method
d.extendleft(items)

print('after: ', d)

Retrieve items from the deque

deque objects similarly contain methods for retrieving items fromm either ends. This is achieved primarily through the pop() and the popleft() methods. The pop() method is used to retrieve an item from the right side of the deque, while the popleft() method is used to retrieve an item from the left side of the deque. Both methods remove the item from the deque  after it has been retrieved. If the deque is empty, both methods will raise an IndexError exception.

Retrieve elements from a deque

from collections import deque

d = deque(range(10))
print('before: ', d)

try: 

    #consume elements from right side
    print('from right')
    print(d.pop(), end = ' ')
    print(d.pop(), end = ' ')
    print(d.pop(), end = ' ')
    print(d.pop(), end = '\n')

    #consume elements from left
    print('from right')
    print(d.popleft(), end = ' ')
    print(d.popleft(), end = ' ')
    print(d.popleft(), end = ' ')
    print(d.popleft(), end = '\n')

except IndexError as e:
    print('done')

print('after: ', d)

Remember that an IndexError will be raised if the deque is empty, you should therefore either handle the exception in advance or ensure  that the deque is not empty before attempting to retrieve elements.

deques and thread safety

deque objects are thread-safe which means that multiple threads can simultaneously read and write from a deque object without any corruption of its items. Thread safety ensures that simultaneous threads can access a shared data structure( or code) without affecting the integrity of the data. 

Rotating deque elements

Rotating the deque means taking elements from the front of the deque to the back and vice verse. We us the rotate() method to perform the rotation. With a negative integer as the argument,  it rotates the deque to the right meaning that elements are taken from back to front. With a positive integer as the argument, it rotates the deque to the left.

negative rotation

from collections import deque

d = deque(range(10))

print('before: ', d)
d.rotate(-5)

print('after: ', d)

positive rotation

from collections import deque

d = deque(range(10))

print('before: ', d)
d.rotate(5)

print('after: ', d)

Deque methods

The methods of deque objects can be summarized as:

method usage
append(x) Adds an element to the front end of the deque.
appendleft(x) Adds an element to the back end of the deque.
clear() Removes all elements from the deque.
count(v) Returns the number of occurrencies of the specified value in the deque.
extend(iterable) Adds all elements of an iterable to the back of the deque.
extendleft(iterable) Adds all elements of an iterable to the front end of the deque.
insert(i, v) Insert value v at index i.
pop() Remove and return the element at the back of the deque. Raises an IndexError exception if the deque is empty.
popleft() Remove and return the element at the front of the deque. Raises an IndexError exception if the deque is empty.
remove(v) Remove the first occurrence of  element  from the deque.
reverse() Reverses the order of the deque elements in place.
rotate() Rotates the deque on either sides by the specified number of elements.

use a method of the deque

from collections import deque

d = deque(range(10))

print('before: ', d)
d.reverse()

print('after: ', d)