Related Articles

Related Articles

Heapq with custom predicate in Python
  • Last Updated : 01 Oct, 2020

Prerequisite: heapq module

The heapq module has several functions that take the list as a parameter and arranges it in a min-heap order. The problem with these functions is they expect either a list or a list of tuples as a parameter. They do not support comparisons between any other iterable or objects. For example, consider a dictionary that has to be maintained in heap.

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

import heapq as hq
  
my_dict={'a':'apple', 'b':'ball', 'c': 'cat'}
hq.heapify(my_dict)
  
print(my_dict)

chevron_right


Output 

TypeError: heap argument must be a list

The heapify() function expects the parameter to be a list. So if we consider a list of dictionaries, look below what happens.

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

import heapq as hq
  
my_dict=[{'a':'apple'}, {'b':'ball'}, {'c': 'cat'}]
  
hq.heapify(my_dict)
  
print(my_dict)

chevron_right


Output:



TypeError: ‘<‘ not supported between instances of ‘dict’ and ‘dict’

Thus, we cannot compare two dictionaries using the heapq module. Sometimes we may have to compare objects of a class and maintain them in a heap. The comparison between such objects is also not feasible with this module.

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

#import module
import heapq as hq
  
# the dictionary to be as heap
my_dict = {'z': 'zebra', 'b': 'ball', 'w': 'whale'
           'a': 'apple', 'm': 'monkey', 'c': 'cat'}
  
# conversion to tuple
my_list = [(k, v) for k, v in my_dict.items()]
  
print("Before organizing as heap :", my_list)
  
# arrange as min-heap
hq.heapify(my_list)
  
print("After organizing as heap :", my_list)
  
# re convert to dictionary
my_dict = dict(my_list)
  
print("Resultant dictionary :", my_dict)

chevron_right


This article discusses how to overcome the above-said issues.

Customizing the sort in heapq

The heapq module functions can take either a list of items or a list of tuples as a parameter. Thus, there are two ways to customize the sorting process:

  1.  Convert the iterable to a list of tuples/list for comparison.
  2.  Write a wrapper class that overrides ‘<‘ operator.

Conversion to list of items

This method is simple and can be used for solving the dictionary comparison problems. The dictionary items can be converted into a list of tuples and then passed to the heapify method.

Example 1: a simple dictionary

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

#import module
import heapq as hq
  
# the dictionary to be as heap
my_dict = {'z': 'zebra', 'b': 'ball', 'w': 'whale',
           'a': 'apple', 'm': 'monkey', 'c': 'cat'}
  
# conversion to tuple
my_list = [(k, v) for k, v in my_dict.items()]
  
print("Before organizing as heap :", my_list)
  
# arrange as min-heap
hq.heapify(my_list)
  
print("After organizing as heap :", my_list)
  
# re convert to dictionary
my_dict = dict(my_list)
  
print("Resultant dictionary :", my_dict)

chevron_right


Output:

Before organizing as heap : [(‘z’, ‘zebra’), (‘b’, ‘ball’), (‘w’, ‘whale’), (‘a’, ‘apple’), (‘m’, ‘monkey’), (‘c’, ‘cat’)]
After organizing as heap : [(‘a’, ‘apple’), (‘b’, ‘ball’), (‘c’, ‘cat’), (‘z’, ‘zebra’), (‘m’, ‘monkey’), (‘w’, ‘whale’)]
Resultant dictionary : {‘a’: ‘apple’, ‘b’: ‘ball’, ‘c’: ‘cat’, ‘z’: ‘zebra’, ‘m’: ‘monkey’, ‘w’: ‘whale’}



Example 2: a list of dictionaries

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

#import module
import heapq as hq
  
# the list of dictionaries to be as heap
my_dict = [{'z': 'zebra'}, {'b': 'ball'}, {'w': 'whale'},
           {'a': 'apple'}, {'m': 'monkey'}, {'c': 'cat'}]
  
# conversion to tuple
my_list = [(k, v) for i in my_dict for k, v in i.items()]
  
print("Before organizing as heap :", my_list)
  
# arrange as min-heap
hq.heapify(my_list)
  
print("After organizing as heap :", my_list)
  
# re convert to dictionary
my_dict = dict(my_list)
  
print("Resultant dictionary :", my_dict)

chevron_right


Output:

Before organizing as heap : [(‘z’, ‘zebra’), (‘b’, ‘ball’), (‘w’, ‘whale’), (‘a’, ‘apple’), (‘m’, ‘monkey’), (‘c’, ‘cat’)]
After organizing as heap : [(‘a’, ‘apple’), (‘b’, ‘ball’), (‘c’, ‘cat’), (‘z’, ‘zebra’), (‘m’, ‘monkey’), (‘w’, ‘whale’)]
Resultant dictionary : {‘a’: ‘apple’, ‘b’: ‘ball’, ‘c’: ‘cat’, ‘z’: ‘zebra’, ‘m’: ‘monkey’, ‘w’: ‘whale’}

The above methods can be used for a dictionary with any data type. 

Using a wrapper class

Consider a situation where the objects of a class have to be maintained in a min-heap.  For example, let us consider a class that has attributes like ‘name‘, ‘designation‘, ‘yos‘(years of service), ‘salary‘. The objects of this class have to be maintained in min-heap based on ‘yos‘ (years of service). 

Here, we override the relational operator ‘<‘ such that it compares the years of service of each employee and returns true or false. Based on the returned boolean value, heapq module arranges the objects in min-heap order.

Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# import required module
import heapq as hq
  
# class definition
class employee:
  
  # constructor
    def __init__(self, n, d, yos, s):
        self.name = n
        self.des = d
        self.yos = yos
        self.sal = s
  
  # function for customized printing
    def print_me(self):
        print("Name :", self.name)
        print("Designation :", self.des)
        print("Years of service :", str(self.yos))
        print("salary :", str(self.sal))
  
   # override the comparison operator
    def __lt__(self, nxt):
        return self.yos < nxt.yos
  
  
# creating objects
e1 = employee('Anish', 'manager', 3, 24000)
e2 = employee('kathy', 'programmer', 2, 15000)
e3 = employee('Rina', 'Analyst', 5, 30000)
e4 = employee('Vinay', 'progammer', 1, 10000)
  
# list of employee objects
emp = [e1, e2, e3, e4]
  
# converting to min-heap
# based on yos
hq.heapify(emp)
  
# printing the results
for i in range(0, len(emp)):
    emp[i].print_me()
    print()

chevron_right


Output

Name : Vinay
Designation : progammer
Years of service : 1
salary : 10000

Name : kathy
Designation : programmer
Years of service : 2
salary : 15000

Name : Rina
Designation : Analyst
Years of service : 5
salary : 30000

Name : Anish
Designation : manager
Years of service : 3
salary : 24000

Attention geek! Strengthen your foundations with the Python Programming Foundation Course and learn the basics.

To begin with, your interview preparations Enhance your Data Structures concepts with the Python DS Course.

My Personal Notes arrow_drop_up
Recommended Articles
Page :