Collections in Python | Collection Modules in Python

FREE Online Courses: Enroll Now, Thank us Later!

Previously you would have heard of many modules like math, random, etc. We will discuss one of the modules that contain special data structures. This module is called the Collections Module in Python. In this article, we will cover different data types in this module, their properties, and their functions. So let us begin.

Python Collections Module

In Python, collections are the data types that store multiple elements like lists, tuples, strings, sets, and dictionaries. Python provides more data structures that can be used as an alternative to the built-in data types. The module named Collections stores all these special data structures. And these are :

1. Counters
2. DefaultDict
3. OrderedDict
4. ChainMap
5. NamedTuple
6. DeQue
7. UserList
8. UserString
9. UserDict

We can use them by importing the module collections, this does not need any prior installation. We can import using the below command.

import collections

We will learn about each of these in detail in the following sections.

Counter in Python

Counters are the data types that store the count of the number of repetitions of elements in an iterable. It stores in the form of a dictionary, with the element as a key and the count as value.

1. Creation of Python counter:

We first import Counter from the collections module in Python and use the Counter() function to declare. The input to the function can either of the following:

a. A dictionary
b. A string
c. A sequence
d. Characters equated to their counts and separated by commas

The below example shows the creation of Counters in these different forms.

from collections import Counter

counter=Counter() #empty counter

counter1=Counter({'a':1,'e':3,'i':6})
print(f"The type of the {counter1} is {type(counter1)}")

counter2=Counter("PythonGeeks")
print(f"The type of the {counter2} is {type(counter2)}")

counter3=Counter([1,3,'A',5.6,"A",3,0])
print(f"The type of the {counter3} is {type(counter3)}")

counter4=Counter(j=4,r=2,i=1,a=3)
print(f"The type of the {counter4} is {type(counter4)}")

Output:

The type of the Counter({‘i’: 6, ‘e’: 3, ‘a’: 1}) is <class ‘collections.Counter’>

The type of the Counter({‘e’: 2, ‘P’: 1, ‘y’: 1, ‘t’: 1, ‘h’: 1, ‘o’: 1, ‘n’: 1, ‘G’: 1, ‘k’: 1, ‘s’: 1}) is <class ‘collections.Counter’>

The type of the Counter({3: 2, ‘A’: 2, 1: 1, 5.6: 1, 0: 1}) is <class ‘collections.Counter’>

The type of the Counter({‘j’: 4, ‘a’: 3, ‘r’: 2, ‘i’: 1}) is <class ‘collections.Counter’>

2. Accessing the values of a counter in Python

We can use the key to get the count of that corresponding key, similar to the dictionary. If we give the non-existing key, then we do not get an error. Instead, we get the count as 0.

Example of accessing the value of a counter:

counter=Counter("PythonGeeks")
counter['e']

counter['a']

Output:

2

0

3. Updating dictionary

We can update the dictionary with additional values by using the update() function. This function can also be used on an empty counter. An example is shown below.

counter=Counter("PythonGeeks")

counter.update('ababc')
counter

Output:

Counter({‘e’: 2, ‘a’: 2, ‘b’: 2, ‘P’: 1, ‘y’: 1, ‘t’: 1, ‘h’: 1, ‘o’: 1, ‘n’: 1, ‘G’: 1, ‘k’: 1, ‘s’: 1, ‘c’: 1})

4. Iterating

We can iterate through the counter and access the values and keys using the loops. An example of doing so with for loop is shown below.

cntr=Counter([1,2,1,0,3,2,1,4,3])
for i in cntr:
    print(f"The count of {i} is {cntr[i]}")

Output:

The count of 1 is 3
The count of 2 is 2
The count of 0 is 1
The count of 3 is 2
The count of 4 is 1

5. Finding the value with high frequencies

We can find the first ‘n’ elements with higher repetitions by using the function most_common(). The function takes the number ‘n’ as an argument and returns the list of ‘n’ tuples, with element and corresponding count.

Example of finding the high frequency values of the counter:

cntr=Counter({'a':3,'r':6,3:9,2.5:1,'t':3})

cntr.most_common(3)

cntr.most_common()

Output:

[(3, 9), (‘r’, 6), (‘a’, 3)]

[(3, 9), (‘r’, 6), (‘a’, 3), (‘t’, 3), (2.5, 1)]

6. Operations in Python Counters

We can also do addition and logical operations on the Counters.

Example of operations the counters:

cntr1=Counter('abacascbb')
cntr2=Counter({'a':3,'b':6,3:2,5.6:1})

cntr1+cntr2

cntr1&cntr2

cntr1|cntr2

Output:

Counter({‘b’: 9, ‘a’: 6, ‘c’: 2, 3: 2, ‘s’: 1, 5.6: 1})

Counter({‘a’: 3, ‘b’: 3})

Counter({‘b’: 6, ‘a’: 3, ‘c’: 2, 3: 2, ‘s’: 1, 5.6: 1})

DefaultDict in Python

This is also a subclass of the dictionaries, that holds a default value for the keys. This prevents the KeyError when we try to access a value corresponding to a non-existing key.

1. Creating Python DefaultDict:

We have to first import defaultdict from the Python collections module. Then use the defaultdict () function for the creation purpose.

a. This function takes the input of the default value using the lambda function to map it. Then we can assign the values using keys, similar to the dictionaries.

b. Or give the type of the values we are going to use in the defaultdict. We can also use the append() function to add the values if the type is the list.

Example of creating defaultdict:

from collections import defaultdict

dDic=defaultdict(lambda:0)

dDic['a']=4
dDic['t']=5.6
dDic[4]=-2

print(f"The type of the {dDic} is {type(dDic)}")

d_Dict=defaultdict(list)
list1=['a','e','i','o','u']
for i in list1:
    d_Dict[i].append(list1.index(i)*2)

d_Dict

Output:

The type of the defaultdict(<function <lambda> at 0x000002885AB98790>, {‘a’: 4, ‘t’: 5.6, 4: -2}) is <class ‘collections.defaultdict’>

defaultdict(<class ‘list’>, {‘a’: [0], ‘e’: [2], ‘i’: [4], ‘o’: [6], ‘u’: [8]})

2. Accessing the values of a defaultdict in Python

We can use the key to get the corresponding value. If the key does not exist, it gives the default value.

Example of accessing the value of a defaultdict:

dDic=defaultdict(lambda:-1)

dDic[1]=2
dDic[3]=4
dDic[5]=6

dDic[1]

dDic[7]

Output:

2

-1

We can also check the default value using a built-in method __missing__(). An example of using this method on the above defaultdict is shown below.

dDic.__missing__(8)

Output:

-1

OrderedDict in Python

This also comes under the category of dictionaries. But this has an additional of keeping track of the order in which the elements are inserted and deleted.

1. Creating Python ordereddict

We can declare the OrderedDict by first importing it from the module and then creating an empty one. Then adding using the keys as done with the dictionaries.

Example of creating ordereddict()

from collections import OrderedDict

oDict=OrderedDict()

oDict['a']=3
oDict['r']=4
oDict['u']=1

print(f"The type of the {oDict} is {type(oDict)}")

Output:

The type of the OrderedDict([(‘a’, 3), (‘r’, 4), (‘u’, 1)]) is <class ‘collections.OrderedDict’>

2. move_to_end() function

This function is used to change the position of the existing pair to either end of the OrderedDict. By default, the position changes to the rightmost side.

To change the position to the leftmost position, we have to give another parameter in addition to the key. This extra argument is called ‘last’ and is True by default. We should set it to False to move to element to the leftmost end.

Example of using move_to_end():

oDict

oDict.move_to_end('r')
oDict

oDict.move_to_end('r',last=False)
oDict

Output:

OrderedDict([(‘a’, 3), (‘r’, 4), (‘u’, 1)])

OrderedDict([(‘a’, 3), (‘u’, 1), (‘r’, 4)])

OrderedDict([(‘r’, 4), (‘a’, 3), (‘u’, 1)])

3. popitem() function in Python

This function is used to delete the item at either end of the Ordered Dict. It normally deletes the item at the rightmost end. To delete from the left side we have to give False to another value called ‘last’.

Example of using popitem():

oDict

oDict.popitem()
oDict

oDict.popitem(last=False)
('a', 3)
oDict

Output:

OrderedDict([(‘a’, 3), (‘r’, 4), (‘u’, 1)])

(‘u’, 1)
OrderedDict([(‘a’, 3), (‘r’, 4)])

(‘a’, 3)
OrderedDict([(‘r’, 4)])

4. Remembrance of the order

As mentioned before, this data structure remembers the order of the modifications done on them. The items get stored in the order of insertion and deletion. The below example shows this.

Example of showing remembrance of the OrderedDict:

oDict=OrderedDict()
oDict[1]=1
oDict[2]=8
oDict[3]=27
oDict[4]=64

for i in oDict:
    print(i,":",oDict[i])

  
oDict.pop(2)
oDict[2]=8

for i in oDict:
    print(i,":",oDict[i])

Output:

1 : 1
2 : 8
3 : 27
4 : 64
8
1 : 1
3 : 27
4 : 64
2 : 8

We can see that the order of the pairs in the ‘oDict’ changed on deleting and inserting the same pair again.

ChainMap in Python

This is a data structure that stores multiple dictionaries under a name. This returns a single list containing all these dictionaries as its elements.

1. Creation of Python ChainMap

We can import the ChainMap from the collections module in Python. Then create the ChainMap using the ChainMap () function with the dictionaries as inputs. The below example shows the creation of a ChainMap.

Example of creating ChainMap:

from collections import ChainMap

dic1={'a':1,'b':2,'c':3}
dic2={'x':-1,'y':-2,'z':-3}
dic3={4:4.2,5:9.0,2:6.1}

cMap=ChainMap(dic1,dic2,dic3)
print(f"The type of the {cMap} is {type(cMap)}")

Output:

The type of the ChainMap({‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1}) is <class ‘collections.ChainMap’>

2. Accessing

To access a value of any dictionary, we can use the corresponding key, as we did in the case of dictionaries. In addition, we can use the keys() and values() functions to get the keys and values respectively. See the below example to access the elements.

Example of accessing the values and keys of ChainMap:

cMap

cMap['y']

cMap.keys()

cMap.values()

Output:

ChainMap({‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1})

-2

KeysView(ChainMap({‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1}))

ValuesView(ChainMap({‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1}))

3. Adding a new dictionary

We can add a new dictionary to the ChainMap using the function new_child(). This function takes the dictionary as an argument and adds this at the beginning of the ChainMap. For example,

Example of adding a new dictionary to ChainMap:

cMap

dic4={1:4,2:9,3:16}

cMap=cMap.new_child(dic4)

print("Modified ChainMap:")
cMap

Output:

ChainMap({‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1})

Modified ChainMap:
ChainMap({1: 4, 2: 9, 3: 16}, {‘a’: 1, ‘b’: 2, ‘c’: 3}, {‘x’: -1, ‘y’: -2, ‘z’: -3}, {4: 4.2, 5: 9.0, 2: 6.1})

NamedTuple in Python

This is similar to a tuple, except that this data structure holds a name for every element. This helps in accessing the elements using the names too, which are easier to remember than the corresponding indexes.

1. Creating Python namedtuple

First, we have to import the data structure namedtuple from the collections module in Python. This function takes two arguments to create a namedtuple. These are the type name and the names of the values in the namedtuple. An important thing to note is that the names/labels have to follow the rules of identifier. The below example shows the.

Example of creating namedtuple:

from collections import namedtuple

nTup=namedtuple('user',['name','password','profession'])
user=nTup('abc','abc_123','student')

print(f"The type of the {user} is {type(user)}")

Output:

The type of the user(name=’abc’, password=’abc_123′, profession=’student’) is <class ‘__main__.user’>

We can also create the namedtuple from dictionaries and iterables. We can use the method _make() in the case of iterables. In the case of dictionaries, we use the ‘**’ operator. For example,

Example of declaring namedtuple:

nTup=namedtuple('squares',['one','tow','three','four','five'])
nTup._make([1,4,8,16,25])

nTup=namedtuple('squares',['one','tow','three','four','five'])
nTup(**{'one':1,'tow':4,'three':9,'four':16,'five':25})

Output:

squares(one=1, tow=4, three=9, four=16, five=25)

squares(one=1, tow=4, three=9, four=16, five=25)

2. Accessing elements

We can access the elements using either of the following methods:
a. Using index
b. Using the name
c. Using the function getattr(), with the arguments as the namedtuple and the key

Example of accessing from namedtuple:

nTup=namedtuple('user',['name','password','profession'])
user=nTup('abc','abc_123','student')

user[1]

user.name
getattr(user,'profession')

Output:

‘abc_123’

‘abc’

‘student’

3. Immutability

Similar to the tuple, the namedtuples do not allow mutability. So we cannot reassign or delete a value. For example,

Example to show immutability of namedtuple:

user[0]='xyz'

user.password='gfds'

Output:

Traceback (most recent call last):
File “<pyshell#74>”, line 1, in <module>
user[0]=’xyz’
TypeError: ‘user’ object does not support item assignment
Traceback (most recent call last):
File “<pyshell#75>”, line 1, in <module>
user.password=’gfds’
AttributeError: can’t set attribute

4. Check names

We can check the names/labels of the namedtuple using the function _fields. For example,

Example of checking the fields/names from namedtuple:

nTup=namedtuple('squares',['one','tow','three','four','five'])
nTup._make([1,4,8,16,25])
nTup._fields

Output:

(‘one’, ‘tow’, ‘three’, ‘four’, ‘five’)

5. Change the values

The namedtuples are immutable, but we can change the values using the method _replace(). For example,

Example of checking the fields/names from namedtuple:

nTup=namedtuple('vowels',['a','e','i','o','u'])

vowels=nTup(1,2,3,4,5)

vowels._replace(a=0)

Output:

vowels(a=0, e=2, i=3, o=4, u=5)

6. Conversion to OrderedDict

We can convert a tuple into an OrderedDict using the function _asdict(). This holds the names as the keys and the elements as the corresponding values. An example is shown below.

Example of checking the fields/names from namedtuple:

nTup=namedtuple('length',['abc','Python','xrt','PythonGeeks'])
length=nTup(3,6,3,11)

oDict=length._asdict()
oDict

Output:

{‘abc’: 3, ‘Python’: 6, ‘xrt’: 3, ‘PythonGeeks’: 11}

DeQue in Python

This is a data structure that allows the inserting and deleting of data from either end at a higher speed. The time complexity of both the operations is O(1), which is lesser compared to that of the lists, O(n).

1. Creation of DeQue

As usual, we have to import deque from the Python collections module. Then use the deque() function with an iterable as input to create the DeQue. The below example shows how to create a DeQue.

Example of creating a deque:

from collections import deque

dQue=deque([1,2,3,4,5])
print(f"The type of the {dQue} is {type(dQue)}")

dQue1=deque('Hello')
dQue1

Output:

The type of the deque([1, 2, 3, 4, 5]) is <class ‘collections.deque’>

deque([‘H’, ‘e’, ‘l’, ‘l’, ‘o’])

2. Insertion

As we can insert the values from both the left and the right ends, we have two functions to do these two operations. The function append() is used to add at the right end and the function appendleft() is used to add at the left end. For example,

Example of inserting values in deque:

dQue=deque(['e','i','o'])

dQue.append('u')
dQue

dQue.appendleft('a')
dQue

Output:

deque([‘e’, ‘i’, ‘o’, ‘u’])

deque([‘a’, ‘e’, ‘i’, ‘o’, ‘u’])

3. Deletion

Similar to the insertion, we have two methods, pop() and popleft() to delta the elements from the right and the left ends respectively. An example of doing these operations is shown below.

Example of deleting values from deque:

dQue=deque('PythonGeeks')
dQue

dQue.pop()
dQue

dQue.popleft()
dQue

Output:

deque([‘P’, ‘y’, ‘t’, ‘h’, ‘o’, ‘n’, ‘G’, ‘e’, ‘e’, ‘k’, ‘s’])

‘s’
deque([‘P’, ‘y’, ‘t’, ‘h’, ‘o’, ‘n’, ‘G’, ‘e’, ‘e’, ‘k’])

‘P’
deque([‘y’, ‘t’, ‘h’, ‘o’, ‘n’, ‘G’, ‘e’, ‘e’, ‘k’])

UserList

This class is a container that resembles the list. In addition, it gives an option to inherit the properties of lists and override the methods according to our needs.

1. Creation

We can first import the UserList from the Python collections module. And then using the UserList() function, we can create a UserList by giving the list as an argument. For example,

Example of creating a UserList:

from collections import UserList
uList=UserList([1,3,5,7,9])
print(f"The type of the {uList} is {type(uList)}")

Output:

The type of the [1, 3, 5, 7, 9] is <class ‘collections.UserList’>

2. Overriding

We can override any of the methods available for the lists. For example, if we want to stop more entries into the list we can create a class and override by raising an exception. This does not affect the other methods. This example is shown below.

Example of overriding methods in a UserList:

from collections import UserList
class UList(UserList):
    def append(self,s=None):
        raise RuntimeError("No more entries allowed")
        
    def extend(self,s=None):
        raise RuntimeError("No more entries allowed")
        
    def insert(self,s=None):
        raise RuntimeError("No more entries allowed")

uList=UList([1,3,5,7,9])

uList.pop()
uList

uList.append(6)

Output:

9
[1, 3, 5, 7]
Traceback (most recent call last):
File “<pyshell#53>”, line 1, in <module>
uList.append(6)
File “<pyshell#49>”, line 3, in append
raise RuntimeError(“No more entries allowed”)
RuntimeError: No more entries allowed

UserString in Python

This class is a container that resembles the strings. It allows us to create our own string with the additional properties and functions, by using the overriding concept.

1. Creation

First, we have to import the UserString from the collections module in Python. Then we can create a UserString using the UserString () function which takes a string as an input. For example,

Example of creating a UserString :

from collections import UserString

uStr=UserString("PythonGeeks")
print(f"The type of the {uStr} is {type(uStr)}")

Output:

The type of the PythonGeeks is <class ‘collections.UserString’>

2. Overriding

We can override any of the methods available for the lists by creating a class with the input as the UserString. This does not affect the other methods.

We might come across the case where we mistyped or missed a character in a string. But appending and modifying are not allowed with the primitive strings, but we can do this with the UserString. An example of making the string mutable is shown below.

Example of overriding methods in a UserString:

class UString(UserString):
    def add(self, char): #adding a character
        self.data = self.data+char
    def modify(self,char1,char2): #change a character
        self.data=self.data.replace(char1,char2)

uStr=UString("PythomGeek")
uStr


uStr.add('s')
uStr


uStr.modify('m','n')
uStr

Output:

‘PythomGeek’

‘PythomGeeks’

‘PythonGeeks’

UserDict in Python

This class is also a container that resembles the dictionary that allows us to inherit the properties of dictionaries and override the methods accordingly.

1. Creation

We can first import the UserDict from the collections module in python. Then using the UserDict ( function. giving the input as a dictionary, we can create a UserDict. For example,

Example of creating a UserDict:

from collections import UserDict

uDic=UserDict({'a':1,'t':4,'y':7})
print(f"The type of the {uDic} is {type(uDic)}")

Output:

The type of the {‘a’: 1, ‘t’: 4, ‘y’: 7} is <class ‘collections.UserDict’>

2. Overriding

Similar to the above cases, we can override any of the available methods and modify the functionality according to our necessity. For example, if we want to remove the property of deletion of the elements from the dictionary we can write the below code.

Example of overriding methods in a UserDict:

class UDict(UserDict):
    def pop(self, ele=None):
        raise RuntimeError("Not allowed to delete")
    def _del_(self):
        raise RuntimeError("Not allowed to delete")
    def popitem(seld, ele=None):
        raise RuntimeError("Not allowed to delete")

  
uDic=UDict({'a':1,'e':2,'i':4,'o':4,'u':5})

uDic['e']=8
uDic

uDic.pop()

Output:

{‘a’: 1, ‘e’: 8, ‘i’: 4, ‘o’: 4, ‘u’: 5}

Traceback (most recent call last):
File “<pyshell#125>”, line 1, in <module>
uDic.pop()
File “<pyshell#121>”, line 3, in pop
raise RuntimeError(“Not allowed to delete”)
RuntimeError: Not allowed to delete

Python Interview Questions on Collections Module

Q1. Write a program to print unique characters of a string.
Ans. We can use the Counter class for this purpose by giving the string as an input. And then printing the keys.

Example of printing unique characters from the string:

from collections import Counter
cntr=Counter('ababaccabcd')
for i in cntr:
    print(i)

Output:

a
b
c
d

Q2. Write a program to reverse the elements using deque.

Ans. We can create another deque. Then run a for loop and appendleft() to the new deque.

Example to reverse a deque in Python:

from collections import deque

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

dQue1=deque()
for i in dQue:
    dQue1.appendleft(i)

dQue1

Output:

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

Q3. Write a program to maintain the details of the patients in the order of their arrival and departure after a checkup.

Ans. We can use OrderedDic for this purpose. The following code shows how to do so.

Example of Python OrderedDict:

from collections import OrderedDict

patients=OrderedDict()

patients['abc']='Problem1'
patients['re']='Problme2'
patients
patients['xyz']='Problem3'

patients.pop('re')

patients

patients['re']='Problem4'
patients

Output:

OrderedDict([(‘abc’, ‘Problem1’), (‘re’, ‘Problme2’)])

OrderedDict([(‘abc’, ‘Problem1’), (‘xyz’, ‘Problem3’)])

OrderedDict([(‘abc’, ‘Problem1’), (‘xyz’, ‘Problem3’), (‘re’, ‘Problem4’)])

Q4. Write a program to print the top 3 most occurring values of a list.

Ans. We can use the counter data structure and use the most_common() function as shown below:

from collections import Counter

cntr=Counter([1,2,3,5,1,7,2,6,8,2,3,4,6,2,1,7,8,7,3])

list1=cntr.most_common(3)
for i in list1:
    print(i[0])

Output:

2
1
3

Q5. Write a function to delete characters of a string.

Ans. We can use the UserString collection and override the pop() function as shown below.

Example to pop characters of a string:

class MyStr(UserString):
  def pop(self,char):
    self.data=self.data.replace(char,"")

    
str=MyStr("PythonGeeks")
str.pop('h')
str

Output:

‘PytonGeeks’

Quiz on Collections in Python

Conclusion

Hence we have learned the different data structures Python provides in the module collections. We have discussed each of the data types in detail. Hope you understood the concepts discussed. Happy learning.

Did we exceed your expectations?
If Yes, share your valuable feedback on Google | Facebook


2 Responses

  1. Aparna says:

    question 6 is giving
    a syntax error for dDict[3]:4…
    NamedError for o

  2. Aparna says:

    question 3 is unclear. both 2 and 3 work for adding

Leave a Reply

Your email address will not be published. Required fields are marked *