2010-10-17 2 views
22

Я хочу держать кучу объектов, а не только цифр. Они будут иметь в них целочисленный атрибут, который куча может сортировать. Самый простой способ использовать кучи в python - heapq, но как я могу сказать, что он сортирует по определенному атрибуту при использовании heapq?Как сделать heapq оценивать кучу определенного атрибута?

ответ

30

heapq сортирует объекты так же, как list.sort делает, так просто определить метод __cmp__() в определении вашего класса, который будет сравнивать себя с другим экземпляром того же класса:

def __cmp__(self, other): 
    return cmp(self.intAttribute, other.intAttribute) 

Работает в Python 2.x.

При использовании 3.x:

def __lt__(self, other): 
    return self.intAttribute < other.intAttribute 
+4

'__cmp__' отсутствует в 3.x. Вместо этого используйте '__lt__'. –

+7

'__lt__' также работает в Python 2, поэтому лучше просто избегать' __cmp__' в целом. –

+8

Точно так же, как вы можете рассказать о любом типе сортировки на основе критериев, отличных от естественной сортировки объекта (например, 'cmp' и' key' для 'sort'), вы должны указать' heapq' для сортировки на основе другой ключ. Другими словами, вам не нужно * переопределять сам объект *, чтобы изменить структуру данных, содержащую его; вы должны просто указать структуру данных. Это замечательная фундаментальная часть, отсутствующая в API 'heapq'. –

3

К сожалению, вы не можете, хотя это часто запрашиваемая функция.

Одним из вариантов было бы вставить (ключ, значение) кортежи в кучу. Однако это не будет работать, если значения генерируют исключение при сравнении (они будут сравниваться в случае связи между клавишами).

Второй вариант заключается в определении метода __lt__ (меньше) в классе, который будет использовать соответствующий атрибут для сравнения элементов для сортировки. Однако это может быть невозможно, если объекты были созданы другим пакетом или если вам нужно их сравнивать по-другому в другом месте программы.

Третий вариант заключается в использовании класса sortedlist из модуля blist (отказ от ответственности: я автор). Конструктор sortedlist принимает параметр key, который позволяет задать функцию, чтобы вернуть ключ сортировки элемента, аналогично параметру list.sort и sortedkey.

+0

Я удалил свой предыдущий комментарий, так как мой вопрос с 'blist' был, вероятно, PEBCAK (опять же спасибо за ваш модуль), так что я только дублирует первую часть предыдущего комментария: всегда можно определить класс с' __lt__ 'либо путем подкласса, либо путем инкапсуляции. – tzot

23

Согласно примеру, из documentation, вы можете использовать кортежи, и он будет сортировать первый элемент кортежа:

>>> h = [] 
>>> heappush(h, (5, 'write code')) 
>>> heappush(h, (7, 'release product')) 
>>> heappush(h, (1, 'write spec')) 
>>> heappush(h, (3, 'create tests')) 
>>> heappop(h) 
(1, 'write spec') 

Так если вы не хотите (или не можете?) сделать метод __cmp__, вы можете вручную извлечь свой ключ сортировки в момент времени.

Обратите внимание, что если первые элементы в паре кортежей равны, будут сравниваться другие элементы. Если это не то, что вы хотите, вам нужно убедиться, что каждый первый элемент уникален.

Смежные вопросы