From 5778de4ad1054501e1564409057224d90f780b56 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 17:37:13 -0700 Subject: [PATCH 01/29] Add files for priorityq --- priorityq.py | 0 test_priorityq.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 priorityq.py create mode 100644 test_priorityq.py diff --git a/priorityq.py b/priorityq.py new file mode 100644 index 0000000..e69de29 diff --git a/test_priorityq.py b/test_priorityq.py new file mode 100644 index 0000000..e69de29 From 10a05e51fd1d969157f2ad68b1db2bec4a51d442 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 17:49:45 -0700 Subject: [PATCH 02/29] Sketch out methods. refs #10 --- priorityq.py | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/priorityq.py b/priorityq.py index e69de29..1d7fac4 100644 --- a/priorityq.py +++ b/priorityq.py @@ -0,0 +1,44 @@ +from __future__ import unicode_literals +from functools import total_ordering + +from binary_heap import BinaryHeap + + +@total_ordering # Will build out the remaining comparison methods +class QueueNode(object): + """A class for a queue node.""" + def __init__(self, val, priority): + super(QueueNode, self).__init__() + self.val = val + self.priority = priority + + def __repr__(self): + """Print representation of node.""" + return "{val}".format(val=self.val) + + def __eq__(self, other): + """Implement this and following two methods with logic to compare + priority and value appropiately. + """ + pass + + def __lt__(self, other): + """Implement in tandem with __eq__.""" + pass + + +class PriorityQ(object): + """A class for a priority queue. Compose this from BinaryHeap.""" + def __init__(self, iterable=()): + pass + + def insert(item): + """Insert an item into the queue.""" + pass + + def pop(): + """Remove the most importan item from the queue.""" + pass + + def peek(): + """Returns the most important item from queue without removal.""" From 91e641ac5d4769ab0fab012357c535f39b9022f0 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 17:54:16 -0700 Subject: [PATCH 03/29] Change node class name --- priorityq.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/priorityq.py b/priorityq.py index 1d7fac4..156adc5 100644 --- a/priorityq.py +++ b/priorityq.py @@ -5,10 +5,10 @@ @total_ordering # Will build out the remaining comparison methods -class QueueNode(object): +class QNode(object): """A class for a queue node.""" def __init__(self, val, priority): - super(QueueNode, self).__init__() + super(QNode, self).__init__() self.val = val self.priority = priority From e90c10093a9948e87008c2cd9411f3abfda00a20 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 17:55:56 -0700 Subject: [PATCH 04/29] Set default priority level to None --- priorityq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/priorityq.py b/priorityq.py index 156adc5..ae91ded 100644 --- a/priorityq.py +++ b/priorityq.py @@ -7,7 +7,7 @@ @total_ordering # Will build out the remaining comparison methods class QNode(object): """A class for a queue node.""" - def __init__(self, val, priority): + def __init__(self, val, priority=None): super(QNode, self).__init__() self.val = val self.priority = priority From b7cdf1540d8b23a90368618f0963382380560b6b Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 18:23:04 -0700 Subject: [PATCH 05/29] Add some QNode tests. refs #11 --- test_priorityq.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test_priorityq.py b/test_priorityq.py index e69de29..29c774e 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -0,0 +1,41 @@ +from __future__ import unicode_literals +import pytest + +from priorityq import PriorityQ, QNode + + +def test_QNode_init_no_priority(): + r = QNode(10) + assert r.val == 10 + assert r.priority is None + + +def test_QNode_init_with_priority(): + p = QNode('string', 0) + assert p.val == 'string' + assert p.priority is 0 + assert p.val, p.priority == ('string', 0) + + +def test_QNode_val_comparison(): + p = QNode(10) + r = QNode(5) + assert p > r + + +def test_QNode_priority_comparison(): + p = QNode(10, 0) + r = QNode(10) + assert p < r + + +def test_QNode_equal_priority_comparison(): + p = QNode(10, 1) + r = QNode(5, 1) + assert p > r + + +def test_QNode_equality_comparison(): + p = QNode(10, 10) + r = QNode(10, 10) + assert p == r From bee27f2500bdc80a436499d2d356a87572065aeb Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 18:59:05 -0700 Subject: [PATCH 06/29] Add tests for insert method --- test_priorityq.py | 109 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 90 insertions(+), 19 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index 29c774e..63f8161 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -4,38 +4,109 @@ from priorityq import PriorityQ, QNode +@pytest.fixture() +def QNode_list(): + QNode_list = [ + QNode(10), + QNode(5, 2), + QNode(100, 1) + ] + return QNode_list + + +@pytest.fixture() +def base_pqueue(QNode_list): + return base_pqueue(QNode_list) + + def test_QNode_init_no_priority(): - r = QNode(10) - assert r.val == 10 - assert r.priority is None + node1 = QNode(10) + assert node1.val == 10 + assert node1.priority is None def test_QNode_init_with_priority(): - p = QNode('string', 0) - assert p.val == 'string' - assert p.priority is 0 - assert p.val, p.priority == ('string', 0) + node1 = QNode('string', 0) + assert node1.val == 'string' + assert node1.priority is 0 + assert node1.val, node1.priority == ('string', 0) def test_QNode_val_comparison(): - p = QNode(10) - r = QNode(5) - assert p > r + node1 = QNode(10) + node2 = QNode(5) + assert node1 > node2 def test_QNode_priority_comparison(): - p = QNode(10, 0) - r = QNode(10) - assert p < r + node1 = QNode(10, 0) + node2 = QNode(10) + assert node1 < node2 def test_QNode_equal_priority_comparison(): - p = QNode(10, 1) - r = QNode(5, 1) - assert p > r + node1 = QNode(10, 1) + node2 = QNode(5, 1) + assert node1 > node2 def test_QNode_equality_comparison(): - p = QNode(10, 10) - r = QNode(10, 10) - assert p == r + node1 = QNode(10, 10) + node2 = QNode(10, 10) + assert node1 == node2 + + +def test_PriorityQ_init_empty(): + pqueue = PriorityQ() + assert isinstance(pqueue, PriorityQ) + assert len(pqueue) == 0 + + +def test_PriorityQ_init_iterable_no_QNodes(): + pqueue = PriorityQ([10, 9, 8, 7, 6, 5]) + assert len(pqueue) == 6 + assert pqueue[0].val == 5 + assert pqueue[0].priority is None + + +def test_PriorityQ_init_iterable_with_QNodes(QNode_list): + pqueue = PriorityQ(QNode_list) + assert len(pqueue) == 3 + assert pqueue[0].val == 100 + assert pqueue[0].priority == 1 + + +def test_insert_item_not_QNode_to_empty(): + queue = PriorityQ() + queue.insert(50) + assert len(queue) == 1 + assert queue[0].val == 50 + assert queue[0].priority is None + + +def test_insert_item_QNode_to_empty(): + node1 = QNode(10, 0) + pqueue = PriorityQ() + pqueue.insert(node1) + assert len(pqueue) == 1 + assert pqueue[0].val == 10 + assert pqueue[0].priority == 0 + + +def test_insert_item_not_QNode_to_filled(base_pqueue): + base_pqueue.insert(500) + assert len(base_pqueue) == 4 + assert base_pqueue[0].val == 100 + assert base_pqueue[0].priority == 1 + + +def test_insert_QNode_to_filled(base_pqueue): + node1 = QNode(10, 0) + base_pqueue.insert(node1) + assert len(base_pqueue) == 4 + assert base_pqueue[0].val == 10 + assert base_pqueue[0].priority == 0 + + +def test_pop(base_pqueue): + From a959390c684363a144143776b6daabae6a4fbeee Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:03:25 -0700 Subject: [PATCH 07/29] Complete first pass simple tests --- test_priorityq.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test_priorityq.py b/test_priorityq.py index 63f8161..c780b6b 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -109,4 +109,15 @@ def test_insert_QNode_to_filled(base_pqueue): def test_pop(base_pqueue): - + top_priority = QNode(9000, 0) + length = len(base_pqueue) + base_pqueue.insert(top_priority) + assert base_pqueue.pop() is top_priority + assert len(base_pqueue) == length - 1 + + +def test_peek(base_pqueue): + top_priority = QNode(9000, 0) + base_pqueue.insert(top_priority) + assert base_pqueue.peek() is top_priority + assert base_pqueue[0] is top_priority From f8e4334514a622fa7541e0b82800fdbc717e8838 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:10:13 -0700 Subject: [PATCH 08/29] Add notes to sketch for priorityq. refs #10 --- priorityq.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/priorityq.py b/priorityq.py index ae91ded..0c6f3ec 100644 --- a/priorityq.py +++ b/priorityq.py @@ -8,7 +8,6 @@ class QNode(object): """A class for a queue node.""" def __init__(self, val, priority=None): - super(QNode, self).__init__() self.val = val self.priority = priority @@ -30,14 +29,20 @@ def __lt__(self, other): class PriorityQ(object): """A class for a priority queue. Compose this from BinaryHeap.""" def __init__(self, iterable=()): + """We can iteratively use insert here.""" pass - def insert(item): - """Insert an item into the queue.""" + def insert(item): # Wamt to extend spec to include priority as 2nd arg + """Insert an item into the queue. Would be nice to examine item as follows: + If item is node: + add to PriorityQ + else: + init QNode with item as val and priority as None + """ pass def pop(): - """Remove the most importan item from the queue.""" + """Remove the most important item from the queue.""" pass def peek(): From 44bc17cd8b271fee4068de1eb1e575b062041425 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:12:59 -0700 Subject: [PATCH 09/29] Add notes to tests. refs #11 --- test_priorityq.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index c780b6b..fc61d43 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -3,6 +3,9 @@ from priorityq import PriorityQ, QNode +# We could parameterize inputs for non-numeric types, but val sorting +# will be odd in binheap. + @pytest.fixture() def QNode_list(): @@ -26,10 +29,9 @@ def test_QNode_init_no_priority(): def test_QNode_init_with_priority(): - node1 = QNode('string', 0) - assert node1.val == 'string' + node1 = QNode(10, 0) + assert node1.val == 10 assert node1.priority is 0 - assert node1.val, node1.priority == ('string', 0) def test_QNode_val_comparison(): From e55cccb6f57f666b7608eb9f96ec023d28b1e737 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:21:36 -0700 Subject: [PATCH 10/29] Add to notes --- priorityq.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/priorityq.py b/priorityq.py index 0c6f3ec..340d9e6 100644 --- a/priorityq.py +++ b/priorityq.py @@ -16,7 +16,7 @@ def __repr__(self): return "{val}".format(val=self.val) def __eq__(self, other): - """Implement this and following two methods with logic to compare + """Implement this and following method with logic to compare priority and value appropiately. """ pass @@ -32,12 +32,13 @@ def __init__(self, iterable=()): """We can iteratively use insert here.""" pass - def insert(item): # Wamt to extend spec to include priority as 2nd arg + def insert(item): # Want to extend spec to add priority as 2nd optional arg """Insert an item into the queue. Would be nice to examine item as follows: If item is node: add to PriorityQ else: init QNode with item as val and priority as None + add to PriorityQ """ pass From 10c22e7e5d871d851bf57b7acb0b4a894198edd5 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:25:45 -0700 Subject: [PATCH 11/29] Fix error in test fixture --- test_priorityq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_priorityq.py b/test_priorityq.py index fc61d43..cabe89c 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -19,7 +19,7 @@ def QNode_list(): @pytest.fixture() def base_pqueue(QNode_list): - return base_pqueue(QNode_list) + return PriorityQ(QNode_list) def test_QNode_init_no_priority(): From c2a2da2c021d597979b448fa1544a52ea48d8b05 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 19:58:21 -0700 Subject: [PATCH 12/29] First pass at script --- priorityq.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/priorityq.py b/priorityq.py index 340d9e6..304b8d0 100644 --- a/priorityq.py +++ b/priorityq.py @@ -19,20 +19,32 @@ def __eq__(self, other): """Implement this and following method with logic to compare priority and value appropiately. """ - pass + if self.priority is None and other.priority is None: + self.value == other.value + elif self.priority is None or other.priority is None: + return False + else: + self.priority == other.priority def __lt__(self, other): """Implement in tandem with __eq__.""" - pass + if self.priority is None and other.priority is None: + self.value < other.value + elif self.priority is None or other.priority is None: + self.priority > other.priority # Since None is less than anything + else: + self.priority < other.priority class PriorityQ(object): """A class for a priority queue. Compose this from BinaryHeap.""" def __init__(self, iterable=()): """We can iteratively use insert here.""" - pass + self.heap = BinaryHeap(iterable=()) + for item in iterable: + self.insert(item) - def insert(item): # Want to extend spec to add priority as 2nd optional arg + def insert(self, item, priority=None): # Want to extend spec to add priority as 2nd optional arg """Insert an item into the queue. Would be nice to examine item as follows: If item is node: add to PriorityQ @@ -40,7 +52,10 @@ def insert(item): # Want to extend spec to add priority as 2nd optional arg init QNode with item as val and priority as None add to PriorityQ """ - pass + if isinstance(item, QNode): + self.heap.push(item) + else: + self.heap.push(QNode(item, priority)) def pop(): """Remove the most important item from the queue.""" From efffab3392cd7cbd8965678f07dd008f7ecc1935 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 20:53:05 -0700 Subject: [PATCH 13/29] Fill out methods --- priorityq.py | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/priorityq.py b/priorityq.py index 304b8d0..f77e5f8 100644 --- a/priorityq.py +++ b/priorityq.py @@ -17,23 +17,25 @@ def __repr__(self): def __eq__(self, other): """Implement this and following method with logic to compare - priority and value appropiately. + priority and val appropiately. """ - if self.priority is None and other.priority is None: - self.value == other.value + if self.priority == other.priority: + return self.val == other.val elif self.priority is None or other.priority is None: return False else: - self.priority == other.priority + return self.priority == other.priority def __lt__(self, other): """Implement in tandem with __eq__.""" - if self.priority is None and other.priority is None: - self.value < other.value - elif self.priority is None or other.priority is None: - self.priority > other.priority # Since None is less than anything + if self.priority == other.priority: + return self.val < other.val + elif self.priority is None: + return False + elif other.priority is None: + return True else: - self.priority < other.priority + return self.priority < other.priority class PriorityQ(object): @@ -44,6 +46,21 @@ def __init__(self, iterable=()): for item in iterable: self.insert(item) + def __repr__(self): + return repr(self.heap) + + def __len__(self): + return len(self.heap) + + def __iter__(self): + return iter(self.heap) + + def __getitem__(self, index): + return self.heap[index] + + def __setitem__(self, index, value): + self.heap[index] = value + def insert(self, item, priority=None): # Want to extend spec to add priority as 2nd optional arg """Insert an item into the queue. Would be nice to examine item as follows: If item is node: @@ -57,9 +74,10 @@ def insert(self, item, priority=None): # Want to extend spec to add priority as else: self.heap.push(QNode(item, priority)) - def pop(): + def pop(self): """Remove the most important item from the queue.""" - pass + return self.heap.pop() - def peek(): + def peek(self): """Returns the most important item from queue without removal.""" + return self.heap[0] From eb4fb77c69e79683e5bb1a8f67dcb7dff4486878 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:04:23 -0700 Subject: [PATCH 14/29] Fix test error --- test_priorityq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_priorityq.py b/test_priorityq.py index cabe89c..c29a828 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -115,7 +115,7 @@ def test_pop(base_pqueue): length = len(base_pqueue) base_pqueue.insert(top_priority) assert base_pqueue.pop() is top_priority - assert len(base_pqueue) == length - 1 + assert len(base_pqueue) == length def test_peek(base_pqueue): From 46582ba85a34c801c63096ee41f5bd35f85e6bba Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:04:37 -0700 Subject: [PATCH 15/29] Complete first pass of script --- priorityq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/priorityq.py b/priorityq.py index f77e5f8..b93026e 100644 --- a/priorityq.py +++ b/priorityq.py @@ -61,7 +61,7 @@ def __getitem__(self, index): def __setitem__(self, index, value): self.heap[index] = value - def insert(self, item, priority=None): # Want to extend spec to add priority as 2nd optional arg + def insert(self, item, priority=None): """Insert an item into the queue. Would be nice to examine item as follows: If item is node: add to PriorityQ From f513c573a11567562d52600da06dc8610f3991a7 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:09:50 -0700 Subject: [PATCH 16/29] Add pretty printing of node val and priority. --- priorityq.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/priorityq.py b/priorityq.py index b93026e..5c1c237 100644 --- a/priorityq.py +++ b/priorityq.py @@ -15,6 +15,10 @@ def __repr__(self): """Print representation of node.""" return "{val}".format(val=self.val) + def __str__(self): + """Pretty print node value and priority.""" + return "{val}, Priority:{p}".format(val=self.val, p=self.priority) + def __eq__(self, other): """Implement this and following method with logic to compare priority and val appropiately. From 784ea9b4fdfa2587e20fb12f4b80a9758f0a3e4d Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:22:34 -0700 Subject: [PATCH 17/29] Improve docstrings --- priorityq.py | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/priorityq.py b/priorityq.py index 5c1c237..b345bb7 100644 --- a/priorityq.py +++ b/priorityq.py @@ -8,6 +8,10 @@ class QNode(object): """A class for a queue node.""" def __init__(self, val, priority=None): + """Initialize a QNode with a value and an optional priority. + + Priority must be an integer, highest being 0. + """ self.val = val self.priority = priority @@ -20,9 +24,7 @@ def __str__(self): return "{val}, Priority:{p}".format(val=self.val, p=self.priority) def __eq__(self, other): - """Implement this and following method with logic to compare - priority and val appropiately. - """ + """Overloads equality comparison to check priority, then value.""" if self.priority == other.priority: return self.val == other.val elif self.priority is None or other.priority is None: @@ -31,7 +33,7 @@ def __eq__(self, other): return self.priority == other.priority def __lt__(self, other): - """Implement in tandem with __eq__.""" + """Overloads lesser than comparison to check priority, then value.""" if self.priority == other.priority: return self.val < other.val elif self.priority is None: @@ -43,9 +45,17 @@ def __lt__(self, other): class PriorityQ(object): - """A class for a priority queue. Compose this from BinaryHeap.""" + """A class for a priority queue.""" def __init__(self, iterable=()): - """We can iteratively use insert here.""" + """Initialize a priority queue, optionally with items from iterable. + + The items in the priority queue are stored in a binary minheap. Items + first sorted by priority, then value. Priority is expressed as an + integer with 0 being the most important. + + args: + iterable: an optional iterable to add to the priority queue. + """ self.heap = BinaryHeap(iterable=()) for item in iterable: self.insert(item) @@ -66,12 +76,15 @@ def __setitem__(self, index, value): self.heap[index] = value def insert(self, item, priority=None): - """Insert an item into the queue. Would be nice to examine item as follows: - If item is node: - add to PriorityQ - else: - init QNode with item as val and priority as None - add to PriorityQ + """Insert an item into the priority queue. + + If the item is a QNode object, it will be added as is. + If not, a new QNode object is created to hold the item with optional + priority assigned. + + args: + item: the item to add (QNode or other value) + priority: the optional integer priority (0 is most important) """ if isinstance(item, QNode): self.heap.push(item) @@ -79,9 +92,9 @@ def insert(self, item, priority=None): self.heap.push(QNode(item, priority)) def pop(self): - """Remove the most important item from the queue.""" + """Remove and return the most important item from the queue.""" return self.heap.pop() def peek(self): - """Returns the most important item from queue without removal.""" + """Return the most important item from queue without removal.""" return self.heap[0] From 9184eb524b8cc842c11942c73fcf4e0a2c84d2e3 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:24:13 -0700 Subject: [PATCH 18/29] Change wording in docstring --- priorityq.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/priorityq.py b/priorityq.py index b345bb7..3ef4eec 100644 --- a/priorityq.py +++ b/priorityq.py @@ -10,7 +10,7 @@ class QNode(object): def __init__(self, val, priority=None): """Initialize a QNode with a value and an optional priority. - Priority must be an integer, highest being 0. + Priority must be an integer, most important being 0. """ self.val = val self.priority = priority From ff88ee350f72327f51a84307d776adbac1eefc04 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:26:55 -0700 Subject: [PATCH 19/29] Improve docstrings --- priorityq.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/priorityq.py b/priorityq.py index 3ef4eec..fe17044 100644 --- a/priorityq.py +++ b/priorityq.py @@ -54,7 +54,8 @@ def __init__(self, iterable=()): integer with 0 being the most important. args: - iterable: an optional iterable to add to the priority queue. + iterable: an optional iterable to add to the priority queue. Items + added this way will be given a priority of None. """ self.heap = BinaryHeap(iterable=()) for item in iterable: From cca2904913cb3e5dd62aeddb13fc81f123da082c Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:50:54 -0700 Subject: [PATCH 20/29] Start tracking insertion order after priority --- priorityq.py | 12 ++++++++---- test_priorityq.py | 28 ++++++++++++++-------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/priorityq.py b/priorityq.py index fe17044..5ad7ae8 100644 --- a/priorityq.py +++ b/priorityq.py @@ -7,13 +7,14 @@ @total_ordering # Will build out the remaining comparison methods class QNode(object): """A class for a queue node.""" - def __init__(self, val, priority=None): + def __init__(self, val, priority=None, order=None): """Initialize a QNode with a value and an optional priority. Priority must be an integer, most important being 0. """ self.val = val self.priority = priority + self.order = order def __repr__(self): """Print representation of node.""" @@ -26,7 +27,7 @@ def __str__(self): def __eq__(self, other): """Overloads equality comparison to check priority, then value.""" if self.priority == other.priority: - return self.val == other.val + return self.order == other.order elif self.priority is None or other.priority is None: return False else: @@ -35,7 +36,7 @@ def __eq__(self, other): def __lt__(self, other): """Overloads lesser than comparison to check priority, then value.""" if self.priority == other.priority: - return self.val < other.val + return self.order < other.order elif self.priority is None: return False elif other.priority is None: @@ -58,6 +59,7 @@ def __init__(self, iterable=()): added this way will be given a priority of None. """ self.heap = BinaryHeap(iterable=()) + self._count = 0 for item in iterable: self.insert(item) @@ -88,9 +90,11 @@ def insert(self, item, priority=None): priority: the optional integer priority (0 is most important) """ if isinstance(item, QNode): + item.order = self._count self.heap.push(item) else: - self.heap.push(QNode(item, priority)) + self.heap.push(QNode(item, priority=priority, order=self._count)) + self._count += 1 def pop(self): """Remove and return the most important item from the queue.""" diff --git a/test_priorityq.py b/test_priorityq.py index c29a828..80115c6 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -11,8 +11,8 @@ def QNode_list(): QNode_list = [ QNode(10), - QNode(5, 2), - QNode(100, 1) + QNode(5, priority=2), + QNode(100, priority=1) ] return QNode_list @@ -29,32 +29,32 @@ def test_QNode_init_no_priority(): def test_QNode_init_with_priority(): - node1 = QNode(10, 0) + node1 = QNode(10, priority=0) assert node1.val == 10 assert node1.priority is 0 -def test_QNode_val_comparison(): - node1 = QNode(10) - node2 = QNode(5) - assert node1 > node2 +def test_QNode_order_comparison(): + node1 = QNode(10, order=1) + node2 = QNode(5, order=2) + assert node1 < node2 def test_QNode_priority_comparison(): - node1 = QNode(10, 0) + node1 = QNode(10, priority=0) node2 = QNode(10) assert node1 < node2 def test_QNode_equal_priority_comparison(): - node1 = QNode(10, 1) - node2 = QNode(5, 1) - assert node1 > node2 + node1 = QNode(10, priority=1, order=1) + node2 = QNode(5, priority=1, order=2) + assert node1 < node2 def test_QNode_equality_comparison(): - node1 = QNode(10, 10) - node2 = QNode(10, 10) + node1 = QNode(10, priority=10) + node2 = QNode(10, priority=10) assert node1 == node2 @@ -67,7 +67,7 @@ def test_PriorityQ_init_empty(): def test_PriorityQ_init_iterable_no_QNodes(): pqueue = PriorityQ([10, 9, 8, 7, 6, 5]) assert len(pqueue) == 6 - assert pqueue[0].val == 5 + assert pqueue[0].order == 0 assert pqueue[0].priority is None From 36c1769b4303b665276a757131846fba0d247231 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 21:52:50 -0700 Subject: [PATCH 21/29] Make priority and order explicit in tests --- test_priorityq.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index 80115c6..7d5df7d 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -87,7 +87,7 @@ def test_insert_item_not_QNode_to_empty(): def test_insert_item_QNode_to_empty(): - node1 = QNode(10, 0) + node1 = QNode(10, priority=0) pqueue = PriorityQ() pqueue.insert(node1) assert len(pqueue) == 1 @@ -103,7 +103,7 @@ def test_insert_item_not_QNode_to_filled(base_pqueue): def test_insert_QNode_to_filled(base_pqueue): - node1 = QNode(10, 0) + node1 = QNode(10, priority=0) base_pqueue.insert(node1) assert len(base_pqueue) == 4 assert base_pqueue[0].val == 10 @@ -111,7 +111,7 @@ def test_insert_QNode_to_filled(base_pqueue): def test_pop(base_pqueue): - top_priority = QNode(9000, 0) + top_priority = QNode(9000, priority=0) length = len(base_pqueue) base_pqueue.insert(top_priority) assert base_pqueue.pop() is top_priority @@ -119,7 +119,7 @@ def test_pop(base_pqueue): def test_peek(base_pqueue): - top_priority = QNode(9000, 0) + top_priority = QNode(9000, priority=0) base_pqueue.insert(top_priority) assert base_pqueue.peek() is top_priority assert base_pqueue[0] is top_priority From 4a898a5f1e670dc30f9f2d247e9a667cc8430ccd Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:01:15 -0700 Subject: [PATCH 22/29] Improve pretty printing --- priorityq.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/priorityq.py b/priorityq.py index 5ad7ae8..af304fd 100644 --- a/priorityq.py +++ b/priorityq.py @@ -22,7 +22,9 @@ def __repr__(self): def __str__(self): """Pretty print node value and priority.""" - return "{val}, Priority:{p}".format(val=self.val, p=self.priority) + return "Value:{val}, Order:{o} Priority:{p}".format( + val=self.val, o=self.order, p=self.priority + ) def __eq__(self, other): """Overloads equality comparison to check priority, then value.""" From 3691c3be2fef96922a244da3c33faefb810b8514 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:07:28 -0700 Subject: [PATCH 23/29] Improve tests --- test_priorityq.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index 7d5df7d..1c3fcb5 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -31,7 +31,7 @@ def test_QNode_init_no_priority(): def test_QNode_init_with_priority(): node1 = QNode(10, priority=0) assert node1.val == 10 - assert node1.priority is 0 + assert node1.priority == 0 def test_QNode_order_comparison(): @@ -67,7 +67,7 @@ def test_PriorityQ_init_empty(): def test_PriorityQ_init_iterable_no_QNodes(): pqueue = PriorityQ([10, 9, 8, 7, 6, 5]) assert len(pqueue) == 6 - assert pqueue[0].order == 0 + assert pqueue[0].val == 10 assert pqueue[0].priority is None @@ -96,10 +96,11 @@ def test_insert_item_QNode_to_empty(): def test_insert_item_not_QNode_to_filled(base_pqueue): - base_pqueue.insert(500) + base_pqueue.insert(500, priority=0) assert len(base_pqueue) == 4 - assert base_pqueue[0].val == 100 - assert base_pqueue[0].priority == 1 + assert base_pqueue[0].val == 500 + assert base_pqueue[0].order == 3 + assert base_pqueue[0].priority == 0 def test_insert_QNode_to_filled(base_pqueue): @@ -107,6 +108,7 @@ def test_insert_QNode_to_filled(base_pqueue): base_pqueue.insert(node1) assert len(base_pqueue) == 4 assert base_pqueue[0].val == 10 + assert base_pqueue[0].order == 3 assert base_pqueue[0].priority == 0 From 439d784384108711c59d78c49fdc21f9e7d52cd6 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:19:54 -0700 Subject: [PATCH 24/29] Fix docstring for queue order tracking --- priorityq.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/priorityq.py b/priorityq.py index af304fd..03b80d0 100644 --- a/priorityq.py +++ b/priorityq.py @@ -10,7 +10,10 @@ class QNode(object): def __init__(self, val, priority=None, order=None): """Initialize a QNode with a value and an optional priority. - Priority must be an integer, most important being 0. + args: + val: the value to store + priority: an integer with 0 being most important + order: integer to store queue insertion order """ self.val = val self.priority = priority @@ -27,7 +30,7 @@ def __str__(self): ) def __eq__(self, other): - """Overloads equality comparison to check priority, then value.""" + """Overloads equality comparison to check priority, then order.""" if self.priority == other.priority: return self.order == other.order elif self.priority is None or other.priority is None: @@ -36,7 +39,7 @@ def __eq__(self, other): return self.priority == other.priority def __lt__(self, other): - """Overloads lesser than comparison to check priority, then value.""" + """Overloads lesser than comparison to check priority, then order.""" if self.priority == other.priority: return self.order < other.order elif self.priority is None: @@ -53,8 +56,8 @@ def __init__(self, iterable=()): """Initialize a priority queue, optionally with items from iterable. The items in the priority queue are stored in a binary minheap. Items - first sorted by priority, then value. Priority is expressed as an - integer with 0 being the most important. + are first sorted by priority, then queue insertion order. Priority is + expressed as an integer with 0 being the most important. args: iterable: an optional iterable to add to the priority queue. Items @@ -83,9 +86,9 @@ def __setitem__(self, index, value): def insert(self, item, priority=None): """Insert an item into the priority queue. - If the item is a QNode object, it will be added as is. - If not, a new QNode object is created to hold the item with optional - priority assigned. + If the item is a QNode object, it will be added tracking queue order. + If not, a new QNode object is created to hold the item with queue order + and optional priority assigned. args: item: the item to add (QNode or other value) From 85aa656e5ea8ad348b9cc90dfbb5e07279b273ce Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:21:01 -0700 Subject: [PATCH 25/29] Remove commment from test --- test_priorityq.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index 1c3fcb5..27f431f 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -3,9 +3,6 @@ from priorityq import PriorityQ, QNode -# We could parameterize inputs for non-numeric types, but val sorting -# will be odd in binheap. - @pytest.fixture() def QNode_list(): From 0a5c6653827f1a372980c40cc165fc07749e41cc Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:48:06 -0700 Subject: [PATCH 26/29] Change pop and peek return to value instead of QNode --- priorityq.py | 4 ++-- test_priorityq.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/priorityq.py b/priorityq.py index 03b80d0..2356a84 100644 --- a/priorityq.py +++ b/priorityq.py @@ -103,8 +103,8 @@ def insert(self, item, priority=None): def pop(self): """Remove and return the most important item from the queue.""" - return self.heap.pop() + return self.heap.pop().val def peek(self): """Return the most important item from queue without removal.""" - return self.heap[0] + return self.heap[0].val diff --git a/test_priorityq.py b/test_priorityq.py index 27f431f..6787f3a 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -113,12 +113,12 @@ def test_pop(base_pqueue): top_priority = QNode(9000, priority=0) length = len(base_pqueue) base_pqueue.insert(top_priority) - assert base_pqueue.pop() is top_priority + assert base_pqueue.pop() is top_priority.val assert len(base_pqueue) == length def test_peek(base_pqueue): top_priority = QNode(9000, priority=0) base_pqueue.insert(top_priority) - assert base_pqueue.peek() is top_priority + assert base_pqueue.peek() is top_priority.val assert base_pqueue[0] is top_priority From 23030155c0309d6f007e32cc9aec0e0d3909f56f Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:52:11 -0700 Subject: [PATCH 27/29] Use '==' instead of 'is' where appropriate --- test_priorityq.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_priorityq.py b/test_priorityq.py index 6787f3a..ec82572 100644 --- a/test_priorityq.py +++ b/test_priorityq.py @@ -113,12 +113,12 @@ def test_pop(base_pqueue): top_priority = QNode(9000, priority=0) length = len(base_pqueue) base_pqueue.insert(top_priority) - assert base_pqueue.pop() is top_priority.val + assert base_pqueue.pop() == top_priority.val assert len(base_pqueue) == length def test_peek(base_pqueue): top_priority = QNode(9000, priority=0) base_pqueue.insert(top_priority) - assert base_pqueue.peek() is top_priority.val + assert base_pqueue.peek() == top_priority.val assert base_pqueue[0] is top_priority From 2c5f347a27f4005d5948993d51789a6ae7afd609 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 22:57:35 -0700 Subject: [PATCH 28/29] Refactor __eq__ --- priorityq.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/priorityq.py b/priorityq.py index 2356a84..9eefd7e 100644 --- a/priorityq.py +++ b/priorityq.py @@ -33,8 +33,6 @@ def __eq__(self, other): """Overloads equality comparison to check priority, then order.""" if self.priority == other.priority: return self.order == other.order - elif self.priority is None or other.priority is None: - return False else: return self.priority == other.priority From b66190059793137f480dfa3737a6301646e361f8 Mon Sep 17 00:00:00 2001 From: Jonathan Stallings Date: Sat, 4 Jul 2015 23:09:13 -0700 Subject: [PATCH 29/29] Remove unneeded _count attribute --- priorityq.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/priorityq.py b/priorityq.py index 9eefd7e..79d3671 100644 --- a/priorityq.py +++ b/priorityq.py @@ -62,7 +62,6 @@ def __init__(self, iterable=()): added this way will be given a priority of None. """ self.heap = BinaryHeap(iterable=()) - self._count = 0 for item in iterable: self.insert(item) @@ -93,11 +92,10 @@ def insert(self, item, priority=None): priority: the optional integer priority (0 is most important) """ if isinstance(item, QNode): - item.order = self._count + item.order = len(self) self.heap.push(item) else: - self.heap.push(QNode(item, priority=priority, order=self._count)) - self._count += 1 + self.heap.push(QNode(item, priority=priority, order=len(self))) def pop(self): """Remove and return the most important item from the queue."""