Как сделать уникальную очередь приоритетов значений в Python?
Python имеет очередь.PriorityQueue, но я не вижу способа сделать каждое значение в нем уникальным, поскольку нет способа проверить, существует ли значение уже (например, find(name) или подобное). Более того, PriorityQueue нуждается в приоритете, чтобы оставаться в пределах ценности, поэтому я не мог даже искать свою ценность, поскольку я также должен был бы знать приоритет. Вы бы использовали (0.5, myvalue) в качестве значения в PriorityQueue, а затем он был бы отсортирован по первому элементу кортежа.
в коллекции.класс deque, с другой стороны, предлагает функцию для проверки, если значение уже существует и является еще более естественным в использовании (без блокировки, но все же атомарным), но он не предлагает способ сортировки по приоритету.
есть некоторые другие реализации в stackoverflow с heapq, но heapq также использует приоритет в пределах значения (например, в первой позиции кортежа), поэтому, похоже, не очень подходит для сравнения уже существующих значений.
создание приоритетная очередь python
https://stackoverflow.com/questions/3306179/priority-queue-problem-in-python
каков наилучший способ создания очереди атомарного приоритета (=может использоваться из нескольких потоков) с уникальными значениями?
пример, что я хотел бы добавить:
- приоритет: 0.2, значение: value1
- приоритет: 0.3, значение: value2
- приоритет: 0.1, значение: value3 (извлекается первым автоматически)
- приоритет: 0.4, значение: value1 (не добавляется снова, даже если он имеет другой приоритет)
3 ответов
вы можете объединить приоритетную очередь с набором:
import heapq
class PrioritySet(object):
def __init__(self):
self.heap = []
self.set = set()
def add(self, d, pri):
if not d in self.set:
heapq.heappush(self.heap, (pri, d))
self.set.add(d)
def get(self):
pri, d = heapq.heappop(self.heap)
self.set.remove(d)
return d
используется очередь приоритетов, указанная в одном из связанных вопросов. Я не знаю, хотите ли вы этого, но довольно легко добавить набор в любую очередь таким образом.
Ну, вот один из способов сделать это. Я в основном начал с того, как они определили PriorityQueue в Queue.py и добавил в него набор для отслеживания уникальных ключей:
from Queue import PriorityQueue
import heapq
class UniquePriorityQueue(PriorityQueue):
def _init(self, maxsize):
# print 'init'
PriorityQueue._init(self, maxsize)
self.values = set()
def _put(self, item, heappush=heapq.heappush):
# print 'put',item
if item[1] not in self.values:
print 'uniq',item[1]
self.values.add(item[1])
PriorityQueue._put(self, item, heappush)
else:
print 'dupe',item[1]
def _get(self, heappop=heapq.heappop):
# print 'get'
item = PriorityQueue._get(self, heappop)
# print 'got',item
self.values.remove(item[1])
return item
if __name__=='__main__':
u = UniquePriorityQueue()
u.put((0.2, 'foo'))
u.put((0.3, 'bar'))
u.put((0.1, 'baz'))
u.put((0.4, 'foo'))
while not u.empty():
item = u.get_nowait()
print item
Боаз Янив опередил меня на несколько минут, но я решил, что тоже отправлю свой, поскольку он поддерживает полный интерфейс PriorityQueue. Я оставил некоторые операторы печати незафиксированными, но прокомментировал те, которые я вставил во время отладки. ;)
в случае, если вы хотите установить приоритет задачи позже.
u = UniquePriorityQueue()
u.put((0.2, 'foo'))
u.put((0.3, 'bar'))
u.put((0.1, 'baz'))
u.put((0.4, 'foo'))
# Now `foo`'s priority is increased.
u.put((0.05, 'foo'))
вот еще одна реализация следует за официальным руководством:
import heapq
import Queue
class UniquePriorityQueue(Queue.Queue):
"""
- https://github.com/python/cpython/blob/2.7/Lib/Queue.py
- https://docs.python.org/3/library/heapq.html
"""
def _init(self, maxsize):
self.queue = []
self.REMOVED = object()
self.entry_finder = {}
def _put(self, item, heappush=heapq.heappush):
item = list(item)
priority, task = item
if task in self.entry_finder:
previous_item = self.entry_finder[task]
previous_priority, _ = previous_item
if priority < previous_priority:
# Remove previous item.
previous_item[-1] = self.REMOVED
self.entry_finder[task] = item
heappush(self.queue, item)
else:
# Do not add new item.
pass
else:
self.entry_finder[task] = item
heappush(self.queue, item)
def _qsize(self, len=len):
return len(self.entry_finder)
def _get(self, heappop=heapq.heappop):
"""
The base makes sure this shouldn't be called if `_qsize` is 0.
"""
while self.queue:
item = heappop(self.queue)
_, task = item
if task is not self.REMOVED:
del self.entry_finder[task]
return item
raise KeyError('It should never happen: pop from an empty priority queue')