{"id":18157072,"url":"https://github.com/goswinr/dicts","last_synced_at":"2026-04-17T13:01:47.519Z","repository":{"id":257805256,"uuid":"763200198","full_name":"goswinr/Dicts","owner":"goswinr","description":"F# Extensions and modules around Dictionary\u003c'T\u003e","archived":false,"fork":false,"pushed_at":"2026-04-06T13:46:44.000Z","size":521,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-06T15:35:46.131Z","etag":null,"topics":["defaultdict","dictionary","fable","fable-libraries","fsharp","library"],"latest_commit_sha":null,"homepage":"https://goswinr.github.io/Dicts/","language":"F#","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/goswinr.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-25T20:05:36.000Z","updated_at":"2026-04-06T13:46:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"c2c2873b-1e81-4d74-9b8d-d23cd3e00931","html_url":"https://github.com/goswinr/Dicts","commit_stats":null,"previous_names":["goswinr/dic","goswinr/dicts"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/goswinr/Dicts","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FDicts","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FDicts/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FDicts/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FDicts/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/goswinr","download_url":"https://codeload.github.com/goswinr/Dicts/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/goswinr%2FDicts/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31930100,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-17T12:37:54.787Z","status":"ssl_error","status_checked_at":"2026-04-17T12:37:25.095Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["defaultdict","dictionary","fable","fable-libraries","fsharp","library"],"created_at":"2024-11-02T06:05:13.997Z","updated_at":"2026-04-17T13:01:47.501Z","avatar_url":"https://github.com/goswinr.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n![Logo](https://raw.githubusercontent.com/goswinr/Dicts/main/Docs/img/logo128.png)\n# Dicts\n\n[![Dicts on nuget.org](https://img.shields.io/nuget/v/Dicts)](https://www.nuget.org/packages/Dicts/)\n[![Build Status](https://github.com/goswinr/Dicts/actions/workflows/build.yml/badge.svg)](https://github.com/goswinr/Dicts/actions/workflows/build.yml)\n[![Docs Build Status](https://github.com/goswinr/Dicts/actions/workflows/docs.yml/badge.svg)](https://github.com/goswinr/Dicts/actions/workflows/docs.yml)\n[![Test Status](https://github.com/goswinr/Dicts/actions/workflows/test.yml/badge.svg)](https://github.com/goswinr/Dicts/actions/workflows/test.yml)\n[![license](https://img.shields.io/github/license/goswinr/Dicts)](LICENSE.md)\n![code size](https://img.shields.io/github/languages/code-size/goswinr/Dicts.svg)\n\n\nThis F# library provides:\n\n- A dedicated `Dict\u003c'T\u003e` type. It is a thin wrapper around `Dictionary\u003c'T\u003e` with more functionality and nicer Error messages.\n\n- A `DefaultDict\u003c'T\u003e` type. It works like [Python's' defaultdict](https://docs.python.org/3/library/collections.html#collections.defaultdict).\u003cbr\u003e\nBy providing a default function in the constructor it will always return a value for any key.\n\n- Extension methods for working with the `IDictionary\u003c'T\u003e` interface.\n\nIt also works in JS and TS with [Fable](https://fable.io/).\n\nThis library was designed for use with F# scripting.\nFunctions and methods never return null.\nOnly functions starting with `try...` will return an F# Option.\nOtherwise when a function fails on invalid input it will throw a descriptive exception.\n\nI was always annoyed that a KeyNotFoundExceptions does not include the actual bad key nor a pretty printed dictionary.\nThis library fixes that in `iDictionary.Get`, `iDictionary.Set` and other item access functions.\n\n## Examples\n\nAll examples assume:\n```fsharp\n#r \"nuget: Dicts\"\nopen Dicts\n```\n\n### Dict — Better error messages\n\n`Dict\u003c'K,'V\u003e` is a thin wrapper around `Dictionary\u003c'K,'V\u003e` that gives descriptive exceptions when a key is missing, including the key, item count, and a pretty-printed dictionary.\n\n```fsharp\n// Create from key-value pairs\nlet d = Dict.create [ \"a\", 1; \"b\", 2; \"c\", 3 ]\n\nd.[\"a\"]          // 1\nd.Get \"b\"        // 2\nd.Set \"d\" 4      // adds or updates key \"d\"\nd.Count          // 4\n\n// Nicer error messages than System.Collections.Generic.Dictionary:\nd.[\"z\"]          // throws KeyNotFoundException:\n                 // \"Dict.get failed to find key \"z\" in Dict\u003c...\u003e of 4 items\"\n\n// Check for keys\nd.ContainsKey \"a\"       // true\nd.DoesNotContainKey \"z\" // true\n\n// Use IsEmpty / IsNotEmpty\nd.IsEmpty       // false\nd.IsNotEmpty    // true\n```\n\n### Dict — Pop and TryPop (Python-like)\n\n```fsharp\nlet d = Dict.create [ \"x\", 10; \"y\", 20 ]\n\nd.Pop \"x\"       // 10  (key \"x\" is removed from d)\nd.Count          // 1\n\nd.TryPop \"y\"     // Some 20  (key \"y\" is removed)\nd.TryPop \"y\"     // None     (already removed, no exception)\n```\n\n### Dict — Conditional set and defaults\n\n```fsharp\nlet d = Dict.create [ \"a\", 1 ]\n\n// Only sets if key is absent, returns true if it was set\nd.SetIfKeyAbsent \"a\" 99  // false  (key \"a\" exists, value stays 1)\nd.SetIfKeyAbsent \"b\" 42  // true   (key \"b\" is now 42)\n\n// Get existing value, or create and store a default\nd.GetOrSetDefaultValue 0 \"c\"   // 0  (key \"c\" is now set to 0)\nd.GetOrSetDefaultValue 0 \"a\"   // 1  (key \"a\" already exists)\n\n// Default from a function that receives the key\nd.GetOrSetDefault (fun k -\u003e k.Length) \"hello\"  // 5\n```\n\n### DefaultDict — Auto-creating missing keys\n\n`DefaultDict\u003c'K,'V\u003e` calls a default function whenever a missing key is accessed.\nThis is inspired by Python's `defaultdict`.\n\n```fsharp\n// Count word occurrences using a mutable ref cell\nlet counter = DefaultDict\u003cstring, int ref\u003e(fun _ -\u003e ref 0)\nfor word in [\"hi\"; \"world\"; \"hi\"; \"hi\"] do\n    incr counter.[word]\n\ncounter.[\"hi\"].Value     // 3\ncounter.[\"world\"].Value  // 1\n\n// Group items by key\nlet groups = DefaultDict\u003cstring, ResizeArray\u003cint\u003e\u003e(fun _ -\u003e ResizeArray())\ngroups.[\"evens\"].Add 2\ngroups.[\"odds\"].Add  1\ngroups.[\"evens\"].Add 4\n\ngroups.[\"evens\"] |\u003e Seq.toList  // [2; 4]\ngroups.[\"odds\"]  |\u003e Seq.toList  // [1]\n```\n\n**Important:** Accessing a missing key with `Get` or the indexer `.[key]` **creates** it.\nUse `TryGetValue` or `ContainsKey` to check without creating:\n```fsharp\nlet dd = DefaultDict\u003cstring, int\u003e(fun _ -\u003e 0)\ndd.ContainsKey \"x\"         // false  (does not create \"x\")\nlet ok, _ = dd.TryGetValue \"x\"  // ok = false  (does not create \"x\")\ndd.[\"x\"]                   // 0  (now \"x\" IS created with the default)\ndd.ContainsKey \"x\"         // true\n```\n\n### Dict module — Functional-style operations\n\nThe `Dict` module provides functions that work on any `IDictionary\u003c'K,'V\u003e`, including plain `Dictionary` and `Dict`.\n\n```fsharp\nlet d = Dict.create [ \"a\", 1; \"b\", 2; \"c\", 3 ]\n\n// Functional get / set / tryGet\nDict.get \"a\" d            // 1\nDict.set \"d\" 4 d          // sets key \"d\" to 4\nDict.tryGet \"z\" d         // None\nDict.tryGet \"a\" d         // Some 1\n\n// Pop and tryPop\nDict.pop \"d\" d             // 4  (removes key \"d\")\nDict.tryPop \"d\" d          // None  (already removed)\n\n// Conditional set\nDict.setIfKeyAbsent \"a\" 99 d  // false  (key \"a\" exists)\nDict.setIfKeyAbsent \"e\" 5 d   // true   (key \"e\" is now 5)\n\n// Get or create a default\nDict.getOrSetDefaultValue 0 \"f\" d   // 0  (key \"f\" is now 0)\n\n// Iteration\nDict.keys   d |\u003e Seq.toList   // [\"a\"; \"b\"; \"c\"; \"e\"; \"f\"]\nDict.values d |\u003e Seq.toList   // [1; 2; 3; 5; 0]\nDict.items  d |\u003e Seq.toList   // [(\"a\",1); (\"b\",2); (\"c\",3); (\"e\",5); (\"f\",0)]\n\nDict.iter (fun k v -\u003e printfn \"%s = %d\" k v) d\nDict.map  (fun k v -\u003e $\"{k}:{v}\") d |\u003e Seq.toList\n```\n\n### Dict.memoize — Cache function results\n\n```fsharp\nlet expensiveComputation = Dict.memoize (fun n -\u003e\n    printfn \"computing %d...\" n\n    n * n\n)\n\nexpensiveComputation 5   // prints \"computing 5...\", returns 25\nexpensiveComputation 5   // returns 25 immediately, no print\n```\n\n### IDictionary extensions\n\nExtension methods available on any `IDictionary\u003c'K,'V\u003e` (including `Dictionary\u003c'K,'V\u003e`):\n```fsharp\nopen Dicts.ExtensionsIDictionary\n\nlet d = System.Collections.Generic.Dictionary\u003cstring,int\u003e()\nd.[\"x\"] \u003c- 10; d.[\"y\"] \u003c- 20; d.[\"z\"] \u003c- 30\n\nd.GetValue \"x\"           // 10  (with descriptive error on missing key)\nd.SetValue \"w\" 40        // adds key \"w\"\nd.Pop \"w\"                // 40  (removes key \"w\")\nd.TryPop \"w\"             // None\nd.Items      |\u003e Seq.toList  // seq of (key, value) tuples\nd.KeysSeq    |\u003e Seq.toList  // seq of keys\nd.ValuesSeq  |\u003e Seq.toList  // seq of values\nd.DoesNotContainKey \"w\"  // true\n```\n\n### Pretty printing\n\nAll types provide readable string representations:\n```fsharp\nlet d = Dict.create [ \"name\", \"Alice\"; \"city\", \"Zurich\" ]\n\nd.ToString()    // \"Dict\u003cString,String\u003e with 2 items\"\nd.AsString      // \"Dict\u003cString,String\u003e with 2 items:\\n  name : Alice\\n  city : Zurich\\n\"\nd.ToString(1)   // prints only the first entry\n```\n\n## Full API Documentation\n\n[goswinr.github.io/Dicts](https://goswinr.github.io/Dicts/reference/dicts.html)\n\n\n## Tests\nAll Tests run in both javascript and dotnet.\nSuccessful Fable compilation to typescript is verified too.\nGo to the tests folder:\n\n```bash\ncd Tests\n```\n\nFor testing with .NET using Expecto:\n\n```bash\ndotnet run\n```\n\nfor JS testing with Fable.Mocha and TS verification:\n\n```bash\nnpm test\n```\n\n## License\n[MIT](https://raw.githubusercontent.com/goswinr/Dicts/main/LICENSE.txt)\n\n## Changelog\nsee [CHANGELOG.md](https://github.com/goswinr/Dicts/blob/main/CHANGELOG.md)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoswinr%2Fdicts","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoswinr%2Fdicts","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoswinr%2Fdicts/lists"}