简体   繁体   中英

Inserting dictionary to heap Python

I'm trying to build a heap with (key, value) so the key is a number and the value is a dictionary.

import heapq
heap = []
dic = {'val_1': 'number_1', 'val_2': 'number_2', 'val_3': 'number_3'}
insetToHeap = (2,dic)
heapq.heappush(heap, insetToHeap)

The code crashes on heappush . The element probably not in the right format.

EDIT:

The error is:

TypeError: unorderable types: dict() < dict()

What is the right way to insert to heap the (number, dic) elements?

Thanks.

Dictionaries can't be ordered, so you need to create something that can keep the dictionary but doesn't use it in comparisons.

Tuples are not a good choice because every element in them might be compared. For example if the first element (your key ) is equal then the second item is compared:

>>> (1, {'a': 1}) < (1, {'a': 2})
TypeError: unorderable types: dict() < dict()

Or with heap :

>>> heap = []
>>> heapq.heappush(heap, (2, {'a': 1}))
>>> heapq.heappush(heap, (2, {'b': 2}))
TypeError: unorderable types: dict() < dict()

If the key is garantueed to be unequal then there's no problem because the second item won't be compared.

In case you just want some storage for the dict you could simply create a class that stores (key, value) but only ever compares the key :

from functools import total_ordering

@total_ordering
class KeyDict(object):
    def __init__(self, key, dct):
        self.key = key
        self.dct = dct

    def __lt__(self, other):
        return self.key < other.key

    def __eq__(self, other):
        return self.key == other.key

    def __repr__(self):
        return '{0.__class__.__name__}(key={0.key}, dct={0.dct})'.format(self)

Insert these into your heap and this will garantuee that the dict won't be compared:

>>> import heapq
>>> heap = []
>>> heapq.heappush(heap, KeyDict(2, {'a': 1}))
>>> heapq.heappush(heap, KeyDict(2, {'b': 2}))
>>> heap
[KeyDict(key=2, dct={'a': 1}), KeyDict(key=2, dct={'b': 2})]

An alternative is to use 3 tuples using a counter as second element that garantuees the comparison won't go to the dict:

>>> from itertools import count
>>> cnt = count()
>>> heap = []
>>> heapq.heappush(heap, (2, next(cnt), {'a': 1}))
>>> heapq.heappush(heap, (2, next(cnt), {'b': 2}))
>>> heap
[(2, 0, {'a': 1}), (2, 1, {'b': 2})]

dict instances cannot be compared in Python 3:

>>> {'a': 9} < {'a': 10}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'

which means neither can your tuples if the first elements are equal:

>>> (2, {'a': 9}) < (3, {'a': 10})
True
>>> (2, {'a': 9}) < (2, {'a': 10})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'dict' and 'dict'
>>>

You need to ensure that the dict s themselves never need to be compared.

So I did a bit of testing and even though you didn't show your full code it would seem that your code is pushing to the heap more than one dict .

>>> heapq.heappush(heap, (0,dic))
>>> heapq.heappush(heap, (0,dic2))
Traceback (most recent call last):
  File "python", line 1, in <module>
TypeError: unorderable types: dict() < dict()

Your heap is comparing the dictionaries because the first item of the list has been compared and so it proceeds to compare the next item, instead you need to do something like:

>>> heapq.heappush(heap, (0,dic))
>>> heapq.heappush(heap, (1,dic))
>>> show_tree(heap)

(0, {'val_1': 'number_1', 'val_2': 'number_2', 'val_3': 'number_3'})
(1, {'val_1': 'number_1', 'val_2': 'number_2', 'val_3': 'number_3'})
------------------------------------

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM