{"id":30327294,"url":"https://github.com/vectorial1024/dictionarylist","last_synced_at":"2026-02-13T08:03:42.632Z","repository":{"id":300806493,"uuid":"1007231594","full_name":"Vectorial1024/DictionaryList","owner":"Vectorial1024","description":"When PHP arrays meet C#: an all-rounded reinterpretation of Lists. ","archived":false,"fork":false,"pushed_at":"2025-07-09T07:33:17.000Z","size":173,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-24T01:25:16.319Z","etag":null,"topics":["array","csharp","dictionary","list"],"latest_commit_sha":null,"homepage":"https://www.nuget.org/packages/Vectorial1024.DictionaryList","language":"C#","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/Vectorial1024.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","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},"funding":{"github":["Vectorial1024"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2025-06-23T17:01:25.000Z","updated_at":"2025-07-09T07:33:20.000Z","dependencies_parsed_at":"2025-06-23T18:26:34.902Z","dependency_job_id":"942e40a0-c717-49de-b93b-2c7878ad2b9d","html_url":"https://github.com/Vectorial1024/DictionaryList","commit_stats":null,"previous_names":["vectorial1024/dictionarylist"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Vectorial1024/DictionaryList","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vectorial1024%2FDictionaryList","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vectorial1024%2FDictionaryList/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vectorial1024%2FDictionaryList/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vectorial1024%2FDictionaryList/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Vectorial1024","download_url":"https://codeload.github.com/Vectorial1024/DictionaryList/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Vectorial1024%2FDictionaryList/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29399430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T06:24:03.484Z","status":"ssl_error","status_checked_at":"2026-02-13T06:23:12.830Z","response_time":78,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["array","csharp","dictionary","list"],"created_at":"2025-08-18T00:09:43.793Z","updated_at":"2026-02-13T08:03:42.615Z","avatar_url":"https://github.com/Vectorial1024.png","language":"C#","funding_links":["https://github.com/sponsors/Vectorial1024"],"categories":[],"sub_categories":[],"readme":"# DictionaryList\n[![GitHub License][github-license-image]][github-repo-url]\n[![NuGet Version][nuget-version-image]][nuget-url]\n[![NuGet Downloads][nuget-downloads-image]][nuget-stats-url]\n[![GitHub Actions Workflow Status][cs-build-status-image]][github-actions-url]\n[![GitHub Repo Stars][github-stars-image]][github-repo-url]\n[![GitHub Sponsors][github-sponsors-image]][github-sponsors-url]\n\nWhen PHP arrays meet C#: an all-rounded reinterpretation of Lists.\n\n## Situation\nConsider a task that uses a `List\u003cT\u003e`:\n- Receive/append many items\n- Remove many elements *in place*: to conserve memory, in case your list is large\n\nWe quickly notice problems when removing many items in-place from `List\u003cT\u003e`:\n- This is actually `O(n^2)`! (where n = number of items in the list)\n- Can't keep old indexes (perhaps we need them for later)\n- Can't do that in a `foreach` loop\n\nWe also notice the problems of the alternatives:\n- `Array\u003cT\u003e` does not automatically resize: tedious memory management\n- It is very slow to insert many data into `Dictionary\u003cint,T\u003e`\n  - By the way, `HashSet\u003cT\u003e` is essentially equivalent to `Dictionary\u003cT,void\u003e`\n- LINQ expressions are usually the fastest, but will require extra memory allocation when building the solution `List\u003cT\u003e`\n- Or, perhaps the problem asks for a `foreach` solution with side effects, such that LINQ is not suitable\n\nThis is a bad situation between a rock and a hard place.\n\nInspired by PHP's highly unconventional approach to implement arrays, lists and maps,\nthis C# package introduces a hybrid between the `List\u003cT\u003e` type and the `Dictionary\u003cTKey,TValue\u003e` type: the `DictionaryList\u003cT\u003e` type.\n\nDo not be afraid of the PHP origin.\nWhile there are some trade-offs when migrating from `List\u003cT\u003e` to `DictionaryList\u003cT\u003e` (see the Characteristics and the Benchmarking sections),\nrest assured that `DictionaryList\u003cT\u003e` really works well.\n\n## Install\nvia NuGet:\n\n```shell\ndotnet add package Vectorial1024.DictionaryList\n```\n\n### Change log\nPlease see `CHANGELOG.md`.\n\n### Todos\nSome todos of this package:\n- Implement the various list interfaces\n- Performance optimization\n\n## Characteristics of `DictionaryList\u003cTValue\u003e`\nConsider the following primer table:\n\n|                      | List Behavior             | Dictionary Behavior      |\n|----------------------|---------------------------|--------------------------|\n| List Structure       | `List\u003cT\u003e`                 | `ListDictionary\u003cint, T\u003e` |\n| Dictionary Structure | 👉 `DictionaryList\u003cT\u003e` 👈 | `Dictionary\u003cint, T\u003e`     |\n\nA `DictionaryList\u003cT\u003e` is a `List\u003cT\u003e` that has `Dictionary`-like structure.\n\nThe theme of a `DictionaryList\u003cT\u003e` is \"deferred reindexing\".\nCompared to a `List\u003cT\u003e`, there are some characteristics/restrictions:\n- No `Insert()`; use `Append()` instead\n- No `RemoveAt()`; use `UnsetAt()` instead, which leaves behind \"memory gaps\"\n- Memory gaps may be reused if you know their indexes; also see `ContainsIndex()`\n- Enumeration yields `KeyValuePair\u003cint,T\u003e` and skips over unset rows\n- No `TrimExcess()`; use `CompactAndTrimExcess()` instead\n- `UnsetAt()` during `foreach` is allowed!\n\nPerhaps this can be better demonstrated with some code sample.\n\n## Usage\nThe API is similar to a `List\u003cT\u003e` (see the docstring or your IDE for the latest info).\nStill, you may consider the following sample code:\n\n```csharp\n// basic usage sample code\n\n// create a new DictionaryList\nvar dictList = new DictionaryList\u003cint\u003e;\n\n// add some items to it\ndictList.Add(1); // index 0\ndictList.Add(2); // index 1\ndictList.Add(3); // index 2\ndictList.Add(4); // index 3\ndictList.Add(5); // index 4\n\n// how many items?\n_ = dictList.Count; // 5\n\n// read from it\n_ = dictList.ContainsIndex(3); // true\n_ = dictList[3]; // 4\n\n// write to it\ndictList[3] = 12;\n_ = dictList[3]; // 12\n// dictList[99] = 99999; // out of bounds; not allowed!\n// dictList[-4] = 42; // out of bounds; not allowed!\n\n// remove from it\n// note: removed items can be GC-ed if that was the last reference to it\ndictList.UnsetAt(1);\n_ = dictList.ContainsIndex(1); // false\n_ = dictList.Count; // 4\n// _ = dictList[1]; // out of bounds; not allowed!\n\n// \"revive\" indexes, but we recommend Add() if you do not care about the value of indexes.\ndictList[1] = 11;\n_ = dictList[1]; // 11;\n\n// let's delete it again...\ndictList.UnsetAt(1);\n\n// ...to demonstrate traversal\nforeach (var kv in dictList) \n{\n    _ = (kv.Key, kv.Value);\n    // yields in order: (0, 1), (2, 3), (3, 12), (4, 5); 4 items!\n}\n\n// we have a gap at index=1; reclaim gaps by doing:\ndictList.CompactAndTrimExcess();\n\n// we are done with the data; clear everything by doing:\ndictList.Clear();\n_ = dictList.Count; // 0\n```\n\n### Thread Safety?\n`DictionaryList\u003cT\u003e` is NOT thread safe!\n\n### Native AOT?\n`DictionaryList\u003cT\u003e` is compatible with Native AOT.\n\n## Benchmarking\nThis package is benchmarked with the BenchmarkDotNet package.\n\nTo run the benchmark:\n\n```shell\n# BenchmarkDotNet strongly recommends benchmarking in Release mode\ndotnet run -c=Release --project=Benchmarking\n```\n\n### Quick performance comparison between relevant collection types\nA benchmark was run with version `0.1.2` of this library. Its detailed results can be found in `BENCHMARK.md`.\n\nBut still, here is a table outlining the performances when `N = 100000`:\n\n| Task                                | List        | DictionaryList | Dictionary | SortedDictionary |\n|-------------------------------------|-------------|----------------|------------|------------------|\n| Append Many Items (speed)           | 155 ms ⭐    | 317 ms 👌      | 1073 ms    | 10507 ms         |\n| Append Many Items (memory)          | 1048976 B ⭐ | 2097536 B 👌   | 6037640 B  | 4800112 B        |\n| Full Iteration (speed)              | 50 ms ⭐     | 176 ms 👌      | 162 ms     | 587 ms           |\n| Full Iteration (memory)             | 0 B         | 48 B           | 0 B        | 312 B            |\n| Read Many Items (speed)             | 17 ms ⭐     | 65 ms 👌       | 147 ms     | 1322 ms          |\n| Read Many Items (memory)            | 0 B         | 0 B            | 0 B        | 0 B              |\n| Remove Many Items In-place (speed)  | 557307 ms   | 789 ms 👌      | 316 ms ⭐   | 810 ms           |\n| Remove Many Items In-place (memory) | 0 B         | 48 B           | 0 B        | 312 B            |\n| Remove Many Items w/ LINQ (speed)   | 104 ms ⭐    | 793 ms 👌      | 885 ms     | 1693 ms          |\n| Remove Many Items w/ LINQ (memory)  | 198072 B ⭐  | 529280 B 👌    | 673168 B   | 1473296 B        |\n| Add Items During `foreach`          | ❌           | ❌ new key      | ❌ new key  | ❌                |\n| Emit Key/Index During `foreach`     | 🤷 [1]      | ✔️             | ✔️         | ✔️               |\n| Replace Items During `foreach`      | 🤷 [1]      | ✔️             | ✔️         | ❌ if key exists  |\n| Remove Items During `foreach`       | ❌           | ✔️             | ✔️         | ❌                |\n\nYou may see that `DictionaryList\u003cT\u003e` is an all-rounded, midway solution between a `List\u003cT\u003e` and a `Dictionary\u003cTKey,TValue\u003e`.\n\nAs part of the benchmark, you may also see that `SortedDictionary\u003cTKey,TValue\u003e` is generally a bad type to use compared to other similar types.\n\nThe following collection types are excluded from the benchmarking:\n- `HashSet\u003cT\u003e`: too similar to `Dictionary\u003cT, void\u003e`, probably has similar performance\n- `OrderedDictionary`: ambiguity between intended `\u003cint, T\u003e` usage and `this[int]` syntax\n- `LinkedList\u003cT\u003e`: unfair/impossible comparison due to lack of index access\n- `SortedList\u003cint,T\u003e`: too similar to `SortedDictionary\u003cint, T\u003e`, probably has similar performance\n\n## Testing\nThis package uses NUnit for testing.\n\nRun the tests with:\n\n```shell\ndotnet test\n```\n\n## Appendix\n[1] Technically, this can be done with Enumerable LINQ's `Index` method, but using LINQ with `foreach` is perhaps an antipattern. \n\n[nuget-url]: https://www.nuget.org/packages/Vectorial1024.DictionaryList/\n[nuget-stats-url]: https://www.nuget.org/stats/packages/Vectorial1024.DictionaryList?groupby=Version\n[github-repo-url]: https://github.com/Vectorial1024/DictionaryList\n[github-actions-url]: https://github.com/Vectorial1024/DictionaryList/actions/workflows/dotnet.yml\n[github-sponsors-url]: https://github.com/sponsors/Vectorial1024\n\n[github-license-image]: https://img.shields.io/github/license/Vectorial1024/DictionaryList?style=plastic\n[nuget-version-image]: https://img.shields.io/nuget/v/Vectorial1024.DictionaryList?style=plastic\n[nuget-downloads-image]: https://img.shields.io/nuget/dt/Vectorial1024.DictionaryList?style=plastic\n[cs-build-status-image]: https://img.shields.io/github/actions/workflow/status/Vectorial1024/DictionaryList/dotnet.yml?style=plastic\n[github-stars-image]: https://img.shields.io/github/stars/vectorial1024/DictionaryList\n[github-sponsors-image]: https://img.shields.io/github/sponsors/Vectorial1024?style=plastic\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvectorial1024%2Fdictionarylist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvectorial1024%2Fdictionarylist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvectorial1024%2Fdictionarylist/lists"}