{"id":15940823,"url":"https://github.com/ofek/depq","last_synced_at":"2025-10-19T03:30:45.810Z","repository":{"id":29163395,"uuid":"32693869","full_name":"ofek/depq","owner":"ofek","description":"CPython double-ended priority queue (DEPQ)","archived":false,"fork":false,"pushed_at":"2017-06-16T19:54:50.000Z","size":53,"stargazers_count":5,"open_issues_count":1,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-29T08:04:16.855Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ofek.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGES.txt","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-22T20:27:23.000Z","updated_at":"2024-01-21T07:49:47.000Z","dependencies_parsed_at":"2022-08-17T19:15:24.340Z","dependency_job_id":null,"html_url":"https://github.com/ofek/depq","commit_stats":null,"previous_names":["ofekmeister/depq"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofek%2Fdepq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofek%2Fdepq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofek%2Fdepq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ofek%2Fdepq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ofek","download_url":"https://codeload.github.com/ofek/depq/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":237056737,"owners_count":19248050,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-07T07:01:24.483Z","updated_at":"2025-10-19T03:30:40.529Z","avatar_url":"https://github.com/ofek.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":".. image:: https://travis-ci.org/Ofekmeister/depq.svg?branch=master\n  :target: https://travis-ci.org/Ofekmeister/depq\n\n.. image:: https://coveralls.io/repos/Ofekmeister/depq/badge.svg?branch=master\n  :target: https://coveralls.io/r/Ofekmeister/depq?branch=master\n\n==================================\ndepq - Double-ended priority queue\n==================================\n\n- Python implementation of a thread-safe and efficient\n  double-ended priority queue (DEPQ) in which items and their\n  priority values are stored in a deque object as tuples.\n- This of course can also be used as a regular priority queue, or\n  simply a FIFO/LIFO queue.\n- Priority queues have many uses such as scheduling, event driven\n  simulation, heuristic analysis, spam filtering, graph searching, etc.\n\nFeatures \u0026 advantages of this implementation:\n---------------------------------------------\n\n- Completely thread-safe\n- Serializable via pickling or JSON\n- Priority values can be ints/floats, numpy types, strings, or\n  any other comparable type you choose!\n- popfirst() and poplast() have O(1) performance instead of\n  running in logarithmic time like in a standard DEPQ or other\n  heap-derived structure\n- Naturally fast also because deque object is implemented in C\n- Items with equal priorities are sorted in the order they were\n  originally added\n- Specific items can be deleted or their priorities changed\n- Membership testing with 'in' operator occurs in O(1) as does\n  getting an item's frequency in DEPQ via count(item)\n\nImplementation:\n---------------\n\n- Priorities are always in proper order, thus, a binary search\n  is performed to find the right index with which to insert new\n  items when specifying priority. Normally, this would result in\n  O(n log n) performance when adding items via insert(item, priority)\n  where self.high() \u003e priority \u003e self.low() because deque (as a\n  doubly linked list) random access is O(n).\n\n  Though, ACTUALLY that is not the case here as I've been able to\n  reduce that to O(n) by modifying the binary search to operate while\n  the internal deque is concurrently rotating.\n\nExamples:\n---------\n\n\u003e\u003e\u003e from textwrap import fill  # For nice wrapped printing\n\u003e\u003e\u003e from depq import DEPQ\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Defaults. If iterable is not None, extend(iterable) will be\n\u003e\u003e\u003e # called (example below). If maxlen is not None, abs(int(maxlen))\n\u003e\u003e\u003e # will become the length limit. If a maxlen is set and an item\n\u003e\u003e\u003e # is added with a priority \u003e lowest prioritized item, it will be\n\u003e\u003e\u003e # added and the last item will be popped. After instantiation, the\n\u003e\u003e\u003e # maxlen can be retrieved with maxlen() and set with set_maxlen(length).\n\u003e\u003e\u003e depq = DEPQ(iterable=None, maxlen=None)\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Add some characters with their ordinal\n\u003e\u003e\u003e # values as priority and keep count\n\u003e\u003e\u003e for c in 'AN_ERRONEOUS_STRING':\n...     count = list(  # This is hacky and not important, skip next 4 lines :)\n...         x + 1 if '{} #{}'.format(c, x + 1) in depq\n...         else next(iter(())) if x != 0 else 0\n...         for x in range(len(depq) + 1)\n...     )[-1]\n...\n...     depq.insert('{} #{}'.format(c, count + 1), ord(c))  # item, priority\n...\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([('_ #1', 95), ('_ #2', 95), ('U #1', 85), ('T #1', 84), ('S #1', 83),\n('S #2', 83), ('R #1', 82), ('R #2', 82), ('R #3', 82), ('O #1', 79), ('O\n#2', 79), ('N #1', 78), ('N #2', 78), ('N #3', 78), ('I #1', 73), ('G #1',\n71), ('E #1', 69), ('E #2', 69), ('A #1', 65)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e # As you can see items with equal priorities are sorted in the order\n\u003e\u003e\u003e # they were originally added. Also note DEPQ root (depq[0]) is highest\n\u003e\u003e\u003e # priority like a max heap.\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.first()\n'_ #1'\n\u003e\u003e\u003e depq.last()\n'A #1'\n\u003e\u003e\u003e depq.high()\n95\n\u003e\u003e\u003e depq.low()\n65\n\u003e\u003e\u003e depq[7]  # Returns tuple(item, priority)\n('R #2', 82)\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.poplast()\n('A #1', 65)\n\u003e\u003e\u003e depq.last()\n'E #2'\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.size()  # Alias for len(DEPQ)\n18\n\u003e\u003e\u003e depq.is_empty()\nFalse\n\u003e\u003e\u003e depq.clear()\n\u003e\u003e\u003e depq.is_empty()\nTrue\n\u003e\u003e\u003e\n\u003e\u003e\u003e # Extend any length iterable of iterables of length \u003e= 2\n\u003e\u003e\u003e depq.extend([('bar', 1, 'arbitrary'), (None, 5), ('foo', 2, 'blah')])\n\u003e\u003e\u003e depq\nDEPQ([(None, 5), ('foo', 2), ('bar', 1)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.clear()\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.addfirst('starter')  # For an empty DEPQ, addfirst \u0026 addlast are\n\u003e\u003e\u003e                           # functionally identical; they add item to DEPQ\n\u003e\u003e\u003e depq                      # with given priority, or default 0\nDEPQ([('starter', 0)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.addfirst('high', depq.high() + 1)\n\u003e\u003e\u003e depq.addlast('low', depq.low() - 1)\n\u003e\u003e\u003e depq\nDEPQ([('high', 1), ('starter', 0), ('low', -1)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.addfirst('higher')  # Default priority DEPQ.high()\n\u003e\u003e\u003e depq.addlast('lower')  # Default priority DEPQ.low()\n\u003e\u003e\u003e depq\nDEPQ([('higher', 1), ('high', 1), ('starter', 0), ('low', -1), ('lower', -1)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.addfirst('highest', 0)  # Invalid priority raises exception\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  File \"C:\\Python34\\lib\\depq.py\", line 340, in addfirst\n    raise ValueError('Priority must be \u003e= '\nValueError: Priority must be \u003e= highest priority.\n\u003e\u003e\u003e\n\u003e\u003e\u003e del depq[0]  # As does del\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\n  File \"C:\\Python34\\lib\\depq.py\", line 639, in __delitem__\n    raise NotImplementedError('Items cannot be deleted by '\nNotImplementedError: Items cannot be deleted by referencing arbitrary indices.\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.clear()\n\u003e\u003e\u003e depq.count(None)\n0\n\u003e\u003e\u003e for i in range(10):\n...     depq.insert(None, i)\n...\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([(None, 9), (None, 8), (None, 7), (None, 6), (None, 5), (None, 4),\n(None, 3), (None, 2), (None, 1), (None, 0)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e None in depq\nTrue\n\u003e\u003e\u003e depq.count(None)\n10\n\u003e\u003e\u003e depq.remove(None)  # Removes item from DEPQ, default # of removals is 1\n[(None, 0)]\n\u003e\u003e\u003e\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([(None, 9), (None, 8), (None, 7), (None, 6), (None, 5), (None, 4),\n(None, 3), (None, 2), (None, 1)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.remove(None, 4)  # As you see, returns list of tuple(item, priority)\n[(None, 1), (None, 2), (None, 3), (None, 4)]\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([(None, 9), (None, 8), (None, 7), (None, 6), (None, 5)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq[None] = 7  # Alias for DEPQ.insert(item, priority)\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([(None, 9), (None, 8), (None, 7), (None, 7), (None, 6), (None, 5)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq.elim(None)  # This simply calls DEPQ.remove(item, -1)\n[(None, 5), (None, 6), (None, 7), (None, 7), (None, 8), (None, 9)]\n\u003e\u003e\u003e print(fill(str(depq), 77))\nDEPQ([])\n\u003e\u003e\u003e\n\u003e\u003e\u003e import pickle  # Pickling won't work if items aren't picklable\n\u003e\u003e\u003e import json  # JSON won't work if items aren't JSON serializable\n\u003e\u003e\u003e\n\u003e\u003e\u003e for i in range(5):\n...     depq.insert([i], i)  # Unhashable types allowed but don't mutate them!\n...\n\u003e\u003e\u003e depq\nDEPQ([([4], 4), ([3], 3), ([2], 2), ([1], 1), ([0], 0)])\n\u003e\u003e\u003e\n\u003e\u003e\u003e binary_depq = pickle.dumps(depq)\n\u003e\u003e\u003e print(fill(str(binary_depq), 77))\nb'\\x80\\x03cdepq\\nDEPQ\\nq\\x00)\\x81q\\x01}q\\x02(X\\x05\\x00\\x00\\x00itemsq\\x03}q\\x0\n4(X\\x03\\x00\\x00\\x00[1]q\\x05K\\x01X\\x03\\x00\\x00\\x00[3]q\\x06K\\x01X\\x03\\x00\\x00\\x\n00[2]q\\x07K\\x01X\\x03\\x00\\x00\\x00[4]q\\x08K\\x01X\\x03\\x00\\x00\\x00[0]q\\tK\\x01uX\\x\n04\\x00\\x00\\x00dataq\\nccollections\\ndeque\\nq\\x0b]q\\x0c(]q\\rK\\x04aK\\x04\\x86q\\x0\ne]q\\x0fK\\x03aK\\x03\\x86q\\x10]q\\x11K\\x02aK\\x02\\x86q\\x12]q\\x13K\\x01aK\\x01\\x86q\\x\n14]q\\x15K\\x00aK\\x00\\x86q\\x16e\\x85q\\x17Rq\\x18X\\x05\\x00\\x00\\x00startq\\x19K\\x00u\nb.'\n\u003e\u003e\u003e\n\u003e\u003e\u003e json_depq = json.dumps(depq.to_json())\n\u003e\u003e\u003e print(fill(json_depq, 77))\n{\"items\": {\"[1]\": 1, \"[3]\": 1, \"[2]\": 1, \"[4]\": 1, \"[0]\": 1}, \"data\": [[[4],\n4], [[3], 3], [[2], 2], [[1], 1], [[0], 0]], \"start\": 0}\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq_from_pickle = pickle.loads(binary_depq)\n\u003e\u003e\u003e depq_from_json = DEPQ.from_json(json_depq)  # Classmethod returns new DEPQ\n\u003e\u003e\u003e\n\u003e\u003e\u003e depq\nDEPQ([([4], 4), ([3], 3), ([2], 2), ([1], 1), ([0], 0)])\n\u003e\u003e\u003e depq_from_pickle\nDEPQ([([4], 4), ([3], 3), ([2], 2), ([1], 1), ([0], 0)])\n\u003e\u003e\u003e depq_from_json\nDEPQ([([4], 4), ([3], 3), ([2], 2), ([1], 1), ([0], 0)])\n\u003e\u003e\u003e\n\nNotes:\n------\n\n- The items in DEPQ are also stored along with their frequency in a\n  separate dict for O(1) lookup. If item is un-hashable, the repr()\n  of that item is stored instead. So 'item in DEPQ' would check the\n  dict for item and if TypeError is raised it would try repr(item).\n- This implementation inserts in the middle in linear time whereas\n  a textbook DEPQ is O(log n). In actual use cases though, this\n  infinitesimal increase in run time is irrelevant, especially when\n  one considers the extra functionality gained coupled with the\n  fact that the other 2 main operations popfirst() and poplast() now\n  occur in constant time.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofek%2Fdepq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fofek%2Fdepq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fofek%2Fdepq/lists"}