{"id":17136087,"url":"https://github.com/wk8/go-ordered-map","last_synced_at":"2025-08-08T00:07:18.519Z","repository":{"id":35131504,"uuid":"185484241","full_name":"wk8/go-ordered-map","owner":"wk8","description":"Optimal implementation of ordered maps for Golang - ie maps that remember the order in which keys were inserted.","archived":false,"fork":false,"pushed_at":"2024-08-16T14:16:33.000Z","size":83,"stargazers_count":530,"open_issues_count":10,"forks_count":40,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-17T12:11:42.590Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wk8.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2019-05-07T22:03:21.000Z","updated_at":"2024-11-12T18:03:10.000Z","dependencies_parsed_at":"2024-06-18T12:33:02.097Z","dependency_job_id":"70481aa2-a4ee-4aa0-b7ba-87f7b6a97a3c","html_url":"https://github.com/wk8/go-ordered-map","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wk8%2Fgo-ordered-map","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wk8%2Fgo-ordered-map/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wk8%2Fgo-ordered-map/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wk8%2Fgo-ordered-map/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wk8","download_url":"https://codeload.github.com/wk8/go-ordered-map/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240271523,"owners_count":19774859,"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-14T20:01:19.527Z","updated_at":"2025-08-08T00:07:18.476Z","avatar_url":"https://github.com/wk8.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"[![Go Reference](https://pkg.go.dev/badge/github.com/wk8/go-ordered-map/v2.svg)](https://pkg.go.dev/github.com/wk8/go-ordered-map/v2)\n[![Build Status](https://circleci.com/gh/wk8/go-ordered-map.svg?style=svg)](https://app.circleci.com/pipelines/github/wk8/go-ordered-map)\n\n# Golang Ordered Maps\n\nSame as regular maps, but also remembers the order in which keys were inserted, akin to [Python's `collections.OrderedDict`s](https://docs.python.org/3.7/library/collections.html#ordereddict-objects).\n\nIt offers the following features:\n* optimal runtime performance (all operations are constant time)\n* optimal memory usage (only one copy of values, no unnecessary memory allocation)\n* allows iterating from newest or oldest keys indifferently, without memory copy, allowing to `break` the iteration, and in time linear to the number of keys iterated over rather than the total length of the ordered map\n* supports any generic types for both keys and values. If you're running go \u003c 1.18, you can use [version 1](https://github.com/wk8/go-ordered-map/tree/v1) that takes and returns generic `interface{}`s instead of using generics\n* idiomatic API, akin to that of [`container/list`](https://golang.org/pkg/container/list)\n* support for JSON and YAML marshalling\n\n## Documentation\n\n[The full documentation is available on pkg.go.dev](https://pkg.go.dev/github.com/wk8/go-ordered-map/v2).\n\n## Installation\n```bash\ngo get -u github.com/wk8/go-ordered-map/v2\n```\n\nOr use your favorite golang vendoring tool!\n\n## Supported go versions\n\nGo \u003e= 1.23 is required to use version \u003e= 2.2.0 of this library, as it uses generics and iterators.\n\nif you're running go \u003c 1.23, you can use [version 2.1.8](https://github.com/wk8/go-ordered-map/tree/v2.1.8) instead.\n\nIf you're running go \u003c 1.18, you can use [version 1](https://github.com/wk8/go-ordered-map/tree/v1) instead.\n\n## Example / usage\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/wk8/go-ordered-map/v2\"\n)\n\nfunc main() {\n\tom := orderedmap.New[string, string]()\n\n\tom.Set(\"foo\", \"bar\")\n\tom.Set(\"bar\", \"baz\")\n\tom.Set(\"coucou\", \"toi\")\n\n\tfmt.Println(om.Get(\"foo\"))          // =\u003e \"bar\", true\n\tfmt.Println(om.Get(\"i dont exist\")) // =\u003e \"\", false\n\n\t// iterating pairs from oldest to newest:\n\tfor pair := om.Oldest(); pair != nil; pair = pair.Next() {\n\t\tfmt.Printf(\"%s =\u003e %s\\n\", pair.Key, pair.Value)\n\t} // prints:\n\t// foo =\u003e bar\n\t// bar =\u003e baz\n\t// coucou =\u003e toi\n\n\t// iterating over the 2 newest pairs:\n\ti := 0\n\tfor pair := om.Newest(); pair != nil; pair = pair.Prev() {\n\t\tfmt.Printf(\"%s =\u003e %s\\n\", pair.Key, pair.Value)\n\t\ti++\n\t\tif i \u003e= 2 {\n\t\t\tbreak\n\t\t}\n\t} // prints:\n\t// coucou =\u003e toi\n\t// bar =\u003e baz\n\t\n\t// removing all pairs which do not have an \"o\" in their key\n\tom.Filter(func(key, value string) bool { return strings.Contains(key, \"o\") })\n\t\n\t// new iteration syntax\n\tfor key, value := range om.FromOldest() {\n\t\tfmt.Printf(\"%s =\u003e %s\\n\", key, value)\n\t}// prints:\n\t// foo =\u003e bar\n\t// coucou =\u003e toi\n}\n```\n\nAn `OrderedMap`'s keys must implement `comparable`, and its values can be anything, for example:\n\n```go\ntype myStruct struct {\n\tpayload string\n}\n\nfunc main() {\n\tom := orderedmap.New[int, *myStruct]()\n\n\tom.Set(12, \u0026myStruct{\"foo\"})\n\tom.Set(1, \u0026myStruct{\"bar\"})\n\n\tvalue, present := om.Get(12)\n\tif !present {\n\t\tpanic(\"should be there!\")\n\t}\n\tfmt.Println(value.payload) // =\u003e foo\n\n\tfor pair := om.Oldest(); pair != nil; pair = pair.Next() {\n\t\tfmt.Printf(\"%d =\u003e %s\\n\", pair.Key, pair.Value.payload)\n\t} // prints:\n\t// 12 =\u003e foo\n\t// 1 =\u003e bar\n}\n```\n\nAlso worth noting that you can provision ordered maps with a capacity hint, as you would do by passing an optional hint to `make(map[K]V, capacity`):\n```go\nom := orderedmap.New[int, *myStruct](28)\n```\n\nYou can also pass in some initial data to store in the map:\n```go\nom := orderedmap.New[int, string](orderedmap.WithInitialData[int, string](\n\torderedmap.Pair[int, string]{\n\t\tKey:   12,\n\t\tValue: \"foo\",\n\t},\n\torderedmap.Pair[int, string]{\n\t\tKey:   28,\n\t\tValue: \"bar\",\n\t},\n))\n```\n\n`OrderedMap`s also support JSON serialization/deserialization, and preserves order:\n\n```go\n// serialization\ndata, err := json.Marshal(om)\n...\n\n// deserialization\nom := orderedmap.New[string, string]() // or orderedmap.New[int, any](), or any type you expect\nerr := json.Unmarshal(data, \u0026om)\n...\n```\n\nSimilarly, it also supports YAML serialization/deserialization using the yaml.v3 package, which also preserves order:\n\n```go\n// serialization\ndata, err := yaml.Marshal(om)\n...\n\n// deserialization\nom := orderedmap.New[string, string]() // or orderedmap.New[int, any](), or any type you expect\nerr := yaml.Unmarshal(data, \u0026om)\n...\n```\n\n## Iterator support (go \u003e= 1.23)\n\nThe `FromOldest`, `FromNewest`, `KeysFromOldest`, `KeysFromNewest`, `ValuesFromOldest` and `ValuesFromNewest` methods return iterators over the map's pairs, starting from the oldest or newest pair, respectively.\n\nFor example:\n\n```go\nom := orderedmap.New[int, string]()\nom.Set(1, \"foo\")\nom.Set(2, \"bar\")\nom.Set(3, \"baz\")\n\nfor k, v := range om.FromOldest() {\n\tfmt.Printf(\"%d =\u003e %s\\n\", k, v)\n}\n\n// prints:\n// 1 =\u003e foo\n// 2 =\u003e bar\n// 3 =\u003e baz\n\nfor k := range om.KeysNewest() {\n\tfmt.Printf(\"%d\\n\", k)\n}\n\n// prints:\n// 3\n// 2\n// 1\n```\n\n`From` is a convenience function that creates a new `OrderedMap` from an iterator over key-value pairs.\n\n```go\nom := orderedmap.New[int, string]()\nom.Set(1, \"foo\")\nom.Set(2, \"bar\")\nom.Set(3, \"baz\")\n\nom2 := orderedmap.From(om.FromOldest())\n\nfor k, v := range om2.FromOldest() {\n\tfmt.Printf(\"%d =\u003e %s\\n\", k, v)\n}\n\n// prints:\n// 1 =\u003e foo\n// 2 =\u003e bar\n// 3 =\u003e baz\n```\n\n## Alternatives\n\nThere are several other ordered map golang implementations out there, but I believe that at the time of writing none of them offer the same functionality as this library; more specifically:\n* [iancoleman/orderedmap](https://github.com/iancoleman/orderedmap) only accepts `string` keys, its `Delete` operations are linear\n* [cevaris/ordered_map](https://github.com/cevaris/ordered_map) uses a channel for iterations, and leaks goroutines if the iteration is interrupted before fully traversing the map\n* [mantyr/iterator](https://github.com/mantyr/iterator) also uses a channel for iterations, and its `Delete` operations are linear\n* [samdolan/go-ordered-map](https://github.com/samdolan/go-ordered-map) adds unnecessary locking (users should add their own locking instead if they need it), its `Delete` and `Get` operations are linear, iterations trigger a linear memory allocation\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwk8%2Fgo-ordered-map","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwk8%2Fgo-ordered-map","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwk8%2Fgo-ordered-map/lists"}