Python Collections: Deque, Counter, DefaultDict, NamedTuple, OrderedDict, ChainMap....

Python Collections Module: Deque In Python, Counter in Python

Python Collection Module, Deque

The Python collections module is a built-in module that provides specialized data structures beyond the built-in data types like lists, tuples, and dictionaries. It offers several useful container datatypes to extend the capabilities of these basic data structures. Here's a brief explanation of some of the key data structures provided by the collections module:

  1. Counter:
    • The Counter is a dictionary subclass that counts the frequency of elements in an iterable (e.g., a list or a string).z
    • It's particularly useful for tasks involving frequency analysis, such as finding the most common elements in a collection.
  2. DefaultDict:
    • defaultdict is a dictionary subclass that allows you to specify a default value for new keys.
    • This is handy when you want to ensure that a key exists in a dictionary, and if it doesn't, it provides a default value rather than raising a KeyError.
  3. NamedTuple:

    • NamedTuple
      is a factory function for creating tuple subclasses with named fields.

    • It provides a way to define simple classes for storing and accessing data using dot notation, which can make your code more readable and maintainable.
  4. Deque:
    • A deque (short for "double-ended queue") is a data structure that allows fast appends and pops from both ends.
    • It's useful for tasks like implementing queues, stacks, or maintaining a sliding window of elements.
  5. OrderedDict:
    • An OrderedDict is a dictionary subclass that remembers the order in which items were added.
    • This ensures that the order of keys is preserved when iterating through the dictionary, which is not guaranteed in a standard dictionary.
  6. ChainMap:
    • ChainMap is used for managing a list of dictionaries as a single unit.
    • It allows you to search multiple dictionaries as if they were a single dictionary, which can be handy for configuration settings or cascading lookups.
  7. UserDict, UserList, and UserString:
    • These are wrapper classes that make it easier to create custom dictionary, list, and string-like objects.
  8. Counter:
    • The collections module also provides a Counter class, which is a dictionary subclass specifically designed for counting hashable objects.
    • It's useful for tasks that involve counting the occurrences of elements in a collection.

These data structures are often more efficient and convenient than rolling your own solutions, making your code more concise and readable. The collections module is an essential part of Python's standard library for working with data structures in various programming scenarios.

 Coding Question:

The collection Module in Python provides different types of containers. A Container is an object that is used to store different objects and provide a way to access the contained objects and iterate over them.

Some of the built-in containers are Tuple, List, Dictionary, etc.
Some of the different containers provided by collections module are discussed below.

Counters

A counter is a container that stores elements as dictionary keys, and their counts are stored as dictionary values.

from collections import Counter

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

print Counter(my_list)

# prints Counter({2: 4, 3: 4, 1: 3, 4: 2, 5: 1})

 

print Counter(my_list).items()

# prints [(1, 3), (2, 4), (3, 4), (4, 2), (5, 1)]

 

print Counter(my_list).keys()

# prints [1, 2, 3, 4, 5]

 

print Counter(myList).values()

# prints [3, 4, 4, 2, 1]

DefaultDict

It’s similar to the usual dictionary (dict) container, but the only difference is that a defaultdict will have a default value if that key has not been set yet. If you didn’t use a defaultdict you’d have to check to see if that key exists, and if it doesn’t, set it to what you want.

from collections import defaultdict 

   

# Defining the dict

# When the int class is passed as the default_factory argument, then a defaultdict is created with default value as zero.

 

d = defaultdict(int) 

    

my_list = [1, 2, 3, 2, 4, 2, 4, 1, 2] 

    

# Iterate through the list for keeping the count 

 

for i in my_list:    

    # The default value is 0 so there is no need to enter the key first 

    d[i] += 1

 

print(d)

# prints defaultdict(<class 'int'>, {1: 2, 2: 3, 3: 1, 4: 2})

OrderedDict

An OrderedDict is a dictionary that remembers the order of the keys that were inserted first. If a new entry overwrites an existing entry, the original insertion position is left unchanged.

from collections import OrderedDict 

 

# Dictionary

d = {} 

d['b'] = 1

d['a'] = 2

d['c'] = 3

d['d'] = 4

   

for key, value in d.items(): 

    print(key, value) 

# This can be printed in any order   

# OrderDictionary

od = OrderedDict() 

od['b'] = 1

od['a'] = 2

od['c'] = 3

od['d'] = 4

   

for key, value in od.items(): 

    print(key, value)

# The order remains same as the key are inserted

ChainMap

A ChainMap encapsulates many dictionaries into a single unit and returns a list of dictionaries.

from collections import ChainMap 

 

d1 = {'a': 1, 'b': 2}

d2 = {'c': 3, 'd': 4}

d3 = {'e': 5, 'f': 6}

 

# Defining the chainmap 

c = ChainMap(d1, d2, d3) 

 

print(c)

# prints ChainMap({'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6})

 

# Accessing Values using key name

print(c['a'])

# prints 1

 

# Accesing values using values() method

print(c.values())

# prints ValuesView(ChainMap({'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}))

 

# Accessing keys using keys() method

print(c.keys())

# prints KeysView(ChainMap({'a': 1, 'b': 2}, {'c': 3, 'd': 4}, {'e': 5, 'f': 6}))

NamedTuple

Basically, namedtuples are easy to create, lightweight object types.
They turn tuples into convenient containers for simple tasks.
With namedtuples, you don’t have to use integer indices for accessing members of a tuple.

from collections import namedtuple

Point = namedtuple('Point','x,y')

pt1 = Point(1,2)

pt2 = Point(3,4)

dot_product = ( pt1.x * pt2.x ) +( pt1.y * pt2.y )

print(dot_product)

# prints 11

Deque

Deque (Doubly Ended Queue) is the optimized list for quicker append and pop operations from both sides of the container. It provides O(1) time complexity for append and pop operations as compared to list with O(n) time complexity.

from collections import deque

d = deque()

d.append(1)

print(d)

# prints deque([1])

 

d.appendleft(2)

print(d)

# prints deque([2, 1])

 

d.clear() # empty the deque

 

d.extend('1')

print(d)

# prints deque(['1'])

 

d.extendleft('234')

print(d)

# prints deque(['4', '3', '2', '1'])

print(d.count('1'))

# prints 1

 

print(d.pop())

# prints '1'

 

print(d)

# prints deque(['4', '3', '2'])

 

print(d.popleft())

# prints '4'

 

print(d)

# prints deque(['3', '2'])

 

d.extend('7896')

print(d)

# prints deque(['3', '2', '7', '8', '9', '6'])

 

d.remove('2')

print(d)

# prints deque(['3', '7', '8', '9', '6'])

 

d.reverse()

print(d)

# prints deque(['6', '9', '8', '7', '3'])

 

d.rotate(3)

print(d)

# prints deque(['8', '7', '3', '6', '9'])

Try the following example in the editor below.

You are given two list of lowercase characters A of length N and B of length M. For each ith character in B print space separated indices of all the occurence of B[i] in A in a new line.

If the character is not present in A, then print -1.
Considered index to be 0-based.

Example Input

A = ['a', 'a', 'b', 'a', 'b', 'c', 'x']

B = ['a', 'x', 'z']

Example Output

0 1 3

6

-1

 

Code:


A = ['a', 'a', 'b', 'a', 'b', 'c', 'x']
B = ['a', 'x', 'z']

# Create a dictionary to store the indices of characters in A
indices_dict = {}

# Populate the dictionary with the indices of characters in A
for idx, char in enumerate(A):
    if char in indices_dict:
        indices_dict[char].append(idx)
    else:
        indices_dict[char] = [idx]

# Iterate through the characters in B and print their indices in A
for char in B:
    if char in indices_dict:
        indices = indices_dict[char]
        print(" ".join(map(str, indices)))
    else:
        print(-1)

Explanation:

To achieve this task, you can iterate through the characters in list B, and for each character, find its indices in list A. You can use a loop and the enumerate function to keep track of the index in list B. Here's a Python program to do that:

This program first creates a dictionary indices_dict to store the indices of characters in list A. It then populates this dictionary with the indices of each character in A. Finally, it iterates through the characters in B, looks up their indices in A from the dictionary, and prints them. If a character in B is not present in A, it prints -1.


Post a Comment

Previous Post Next Post