Skip to content Skip to sidebar Skip to footer

Descending Order Using Heapq

I am using heapq module of Python get data in ascending and descending order. For ascending, I am using min heap and it works well as follow: >>> from heapq import heapify

Solution 1:

As we discussed in the comments, your concerns about copying data when using negated values to flip a min-heap into a max-heap don't matter when you're starting with an empty heap and adding the values as you go. Since that's the use case when finding the running median of a stream of values, negating the values as you add them should work just fine.

Here's a running median generator I wrote just to double check that it works the way I expected:

def running_median(iterable):
    left_q = [] # heap of smaller-than-median elements, stored negated
    right_q = [] # heap of larger-than-median elementsfor value in iterable:
        if len(left_q) == len(right_q): # push to left_q when they're equal sizeif len(right_q) > 0and value > right_q[0]:
                value = heapq.heapreplace(right_q, value)
            heapq.heappush(left_q, -value)
        else: # push to right_q only when it's (strictly) smallerif value < -left_q[0]:
                value = -heapq.heapreplace(left_q, -value)
            heapq.heappush(right_q, value)

        # len(left_q) is always >= len(right_q) so we never yield right_q[0]if len(left_q) > len(right_q):
            yield -left_q[0]else:
            yield (-left_q[0] + right_q[0]) / 2

The left_q heap stores the less-than-or-equal-to-median values. Each value is negated when it's pushed, so using the normal min-heap operations on it makes it work like a max-heap. We just need to remember to re-negate any value we take out of it, to get back to the original sign.

Solution 2:

I think you are looking instead for a sorted linked list in this case, I modify someone I found here so it will insert with ascending order (I added the pop function, for some reason it wasn't in the code, but I think you may need it):

# Python program to insert in sorted list# Node class classNode:

    # Constructor to initialize the node objectdef__init__(self, data):
        self.data = data
        self.next = NoneclassLinkedList:

    # Function to initialize headdef__init__(self):
        self.head = NonedefsortedInsert(self, new_node):

        # Special case for the empty linked list if self.head isNone:
            new_node.next = self.head
            self.head = new_node

        # Special case for head at endelif self.head.data <= new_node.data:
            new_node.next = self.head
            self.head = new_node

        else :

            # Locate the node before the point of insertion
            current = self.head
            while(current.nextisnotNoneand
                 current.next.data > new_node.data):
                current = current.next

            new_node.next = current.next
            current.next = new_node

    # Function to insert a new node at the beginningdefpush(self, new_data):
        new_node = Node(new_data)
        new_node.next = self.head
        self.head = new_node

    # Utility function to prit the linked LinkedListdefprintList(self):
        temp = self.head
        while(temp):
            print(temp.data),
            temp = temp.nextdefpop(self):
        val = self.head.data
        self.head = self.head.nextreturn val


# Driver program
llist = LinkedList()
new_node = Node(5)
llist.sortedInsert(new_node)
new_node = Node(10)
llist.sortedInsert(new_node)
new_node = Node(7)
llist.sortedInsert(new_node)
new_node = Node(3)
llist.sortedInsert(new_node)
new_node = Node(1)
llist.sortedInsert(new_node)
new_node = Node(9)
llist.sortedInsert(new_node)
print("Create Linked List")
llist.printList()

As you can see, it was just change the >= to <=, it does the job perfectly

Solution 3:

There are private methods for this (tested at python 3.8)

import heapq


if __name__ == '__main__':
    a = [1, 3, 2, 5]

    heapq._heapify_max(a)

    for item inrange(0, len(a)):
        print(heapq._heappop_max(a)

And result is

sorted heap  5
sorted heap  3
sorted heap  2
sorted heap  1

But using of private methods maybe looks not enough correct for somebody. For this reason we can change ordering with placing your object inside modified wrapper

classDescOrder:
    def__init__(self, entity):
        self.entity = entity

    def__lt__(self, o):
        return self.entity.__gt__(o.entity)

    def__repr__(self):
        returnstr(self.entity)

defcheck_sorting(a, b):
    new_heap = []

    for element in a:
        heapq.heappush(new_heap, DescOrder(element))

    for index inrange(0, len(b)):
        assert heapq.heappop(new_heap).entity == b[index]


if __name__ == '__main__':
    check_sorting([5, 1, -1, 3, 2], [5, 3, 2, 1, -1])
    check_sorting([5, 2, -1, 3, 1], [5, 3, 2, 1, -1])
    check_sorting([-1, 2, 5, 3, 1], [5, 3, 2, 1, -1])
 

Post a Comment for "Descending Order Using Heapq"