{"id":19392066,"url":"https://github.com/davidraab/queue","last_synced_at":"2026-06-20T05:02:37.362Z","repository":{"id":197203281,"uuid":"451077122","full_name":"DavidRaab/Queue","owner":"DavidRaab","description":"F#: Immutable Queue","archived":false,"fork":false,"pushed_at":"2022-08-31T20:15:45.000Z","size":130,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-24T21:12:32.995Z","etag":null,"topics":["data-structure","fsharp","library","queue"],"latest_commit_sha":null,"homepage":"","language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DavidRaab.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-01-23T11:00:19.000Z","updated_at":"2024-12-30T16:29:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"ec9b8ce8-426e-4551-9c29-b9908bde89c1","html_url":"https://github.com/DavidRaab/Queue","commit_stats":null,"previous_names":["davidraab/queue"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/DavidRaab/Queue","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DavidRaab%2FQueue","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DavidRaab%2FQueue/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DavidRaab%2FQueue/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DavidRaab%2FQueue/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DavidRaab","download_url":"https://codeload.github.com/DavidRaab/Queue/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DavidRaab%2FQueue/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34557553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["data-structure","fsharp","library","queue"],"created_at":"2024-11-10T10:30:17.799Z","updated_at":"2026-06-20T05:02:37.347Z","avatar_url":"https://github.com/DavidRaab.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# F#: Immutable Queue\n\nA **Queue** is a *first-in-first-out* data-structure. It provides fast appending O(1) to the end of a **Queue** but also\nfast prepeding O(1) to a **Queue**.\n\nThe immutable **List** provided by F# is a *first-in-last-out* data-structure or a **Stack** and only provides fast prepeding O(1).\n\nThis **Queue** implements all the functions you know from the **List** module with a few more and some changes. **Queue** is designed as a replacement for **List**, but not as a drop-in replacement.\n\n# Design Philosophy / Why you want to use Queue\n\nThe Design Philosophy of `Queue` opposed to `List` is:\n\n1. To never throw an Exception.\n2. Use `ValueOption` instead of `Option`.\n\nTo achieve the first goal some functions are changed to return a `ValueOption`, provide reasonable results like\nreturning an empty **Queue** or provide input checking for arguments.\n\nList already provides some of these. For example you have `List.find` and `List.tryFind`. In this module there\nis only `Queue.find` and it will return a `ValueOption` by default. There is no *find* version that will throw\nan exception.\n\nBut the `List` module still have a lot of functions that throw exceptions in various ways with\nno equivalent *try* function.\n\n```fsharp\n// Throws ArgumentException\nlet bs = List.map2 (fun x y -\u003e x + y) [1..10] [1..8]\n\n// Queue [2;4;6;8;10;12;14;16]\nlet cs = Queue.map2 (fun x y -\u003e x + y) (Queue.range 1 10) (Queue.range 1 8)\n\n// Throws ArgumentException\nlet ds = List.tail []\n\n// Queue.empty\nlet es = Queue.tail Queue.empty\n\n// Throws InvalidOperationException\nlet fs = List.take 5 [1;2;3]\n\n// Queue [1;2;3]\nlet gs = Queue.take 5 (Queue [1;2;3])\n```\n\nFunctions are either changed to return something useful like `Queue.map2` that only iterates\non so many elements that are possible on both `Queue`s . Or if not possible, are changed to\nreturn an `ValueOption` instead.\n\n```fsharp\n// Throws an ArgumentException\nlet xs = List.reduce (fun x y -\u003e x + y) []\n\n// ValueNone\nlet ys = Queue.reduce (fun x y -\u003e x + y) Queue.empty\n\n// ValueSome 55\nlet zs = Queue.reduce (fun x y -\u003e x + y) (Queue.range 1 10)\n```\n\nAs an overview. There are still these `List` functions that can throw exceptions and have no *try* equivalent you must consider when you use a `List`: `average`, `averageBy`, `chunkBySize`, `exactlyOne`, `except`, `exists2`, `forall2`,\n`head`, `init`, `insertAt`, `insertManyAt`, `item`, `last`, `max`, `maxBy`, `min`,\n`minBy`, `permute`, `reduce`, `reduceBack`, `removeAt`, `removeManyAt`, `skip`, `splitAt`, `splitInto`, `tail`,\n`take`, `transpose`, `updateAt`, `windowed`.\n\nNone of those throw an exception in the `Queue` implementation!\n\nOn top, there are additional functions you don't find in other modules. To name the most important.\n\n* `Queue.map3`, `Queue.map4`\n* `Queue.lift2`, `Queue.lift3`, `Queue.lift4`\n* `Queue.fold3`, `Queue.fold4`, `Queue.foldi`, `Queue.foldi2`, `Queue.foldi3`, `Queue.foldi4`\n* `Queue.choosei`\n* `Queue.mapFold` (it works different to `List.mapFold`)\n* `Queue.mapReduce`\n* `Queue.mapFilter`\n* `Queue.filterMap`\n* `Queue.toSet`, `Queue.toMap`, `Queue.toMapWithFold`, `Queue.toMapGroupBy`\n* `Queue.ofList2`, `Queue.toList2`\n* `Queue.sliceGrow`, `Queue.insertAtGrow`, `Queue.updateAtGrow`, `Queue.insertManyAtGrow`\n* `Queue.findRemove`\n* `Queue.intersperse`\n* `Queue.permutations`\n* `Queue.partitionMap`\n* `Queue.itemMany`\n* `Queue.swap`, `Queue.swapMany`\n\nBecause of the implementation of the Queue some operations have a better performance.\n\n* Adding `Queue.add` and prepending `Queue.prepend` are both O(1)\n* `Queue.rev` is O(1)\n* `Queue.length` is O(1)\n* `Queue.append` is O(N) of the smaller list.\n\n`Queue` also implements Comparision, Equality and IEnumerable (Seq) so you can compare two `Queue`s, traverse it with the `for` keyword or pass it wherever a `seq` is needed.\n\nYou can also transform every sequence to a Queue by just writing `Queue` in front of it. Like you are used with `Map` or `Set`.\n\n```fsharp\nlet bs = Queue [1..10]\nlet cs = Queue [|1..10|]\nlet ds = Queue (seq {1..10})\n\n// Queue\u003cKeyValuePair\u003cint,string\u003e\u003e\nlet m1 = Queue       (Map [(1,\"Hi\"); (10,\"There\")]\n\n// Queue\u003cint * string\u003e\nlet m2 = Queue.ofMap (Map [(1,\"Hi\"); (10,\"There\")]\n```\n\nFor usage, currently, it is best to just look into the test file in [../test/Program.fs](https://github.com/DavidRaab/Queue/blob/master/test/Program.fs)\n\n# Implementation Details\n\nThe internal data-structure is quite easy to understand. It keeps track of three values. Two immutable lists and the amount of elements in the Queue.\n\nAdded items to the Queue are added to a List named `Added`. This way we can provide O(1) for adding elements.\n\nWhen you traverse the Queue it will traverse the internal `Queue` list that has the items in Queue-order. If that is empty, it will reverse the `Added` list once and store the result into `Queue`. This way traversing is amortized O(1). Meaning: Most operations are O(1) and some are O(N).\n\nSo if you do the following:\n\n```fsharp\nlet bs = Queue.range 1 10\nlet cs = Queue.add 11 bs\nlet ds = Queue.skip 3 cs\nlet es = ds |\u003e Queue.add 12 |\u003e Queue.add 13 |\u003e Queue.add 14\nlet fs = Queue.prepend 3 es\nlet gs = Queue.skip 3 fs\n```\n\nThe internal data-structure would look like these:\n\n```fsharp\nlet bs = Queue([], [10;9;8;7;6;5;4;3;2;1], 10)\nlet cs = Queue([], [11;10;9;8;7;6;5;4;3;2;1], 11)\nlet ds = Queue([4;5;6;7;8;9;10;11], [], 8)\nlet es = Queue([4;5;6;7;8;9;10;11], [14;13;12], 11)\nlet fs = Queue([3;4;5;6;7;8;9;10;11], [14;13;12], 12)\nlet gs = Queue([6;7;8;9;10;11], [14;13;12], 9)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidraab%2Fqueue","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavidraab%2Fqueue","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavidraab%2Fqueue/lists"}