Skip to main content
OrderedMap is a generic key-value map that guarantees iteration order. Unlike Go’s built-in map, which randomizes iteration, OrderedMap lets you control whether order is stable (insertion order, even after updates) or recency-based (most recently written key comes last — useful for LRU caches).

Installation

import "github.com/fgm/container/orderedmap"

Constructor

func NewSlice[K comparable, V any](sizeHint int, stable bool) *Slice[K, V]
sizeHint
int
required
A hint for the initial capacity of the internal slice and map. Use 0 if you have no estimate. This does not limit the maximum size.
stable
bool
required
Controls what happens when you Store a key that already exists.
  • truestable mode: the key keeps its original insertion position in the order. Useful when you care about when a key first appeared.
  • falserecency mode: the key is moved to the end of the order on every write. Useful for LRU caches where the most recently touched entry should appear last.

Methods

MethodSignatureDescription
StoreStore(key K, value V)Inserts or updates a key-value pair. In recency mode, updates an existing key’s position to the end.
LoadLoad(key K) (value V, loaded bool)Returns the value for a key. loaded is false if the key is absent.
DeleteDelete(key K)Removes a key and its value. No-op if the key is absent.
RangeRange(func(key K, value V) bool)Iterates over all entries in insertion/recency order. Return false from the callback to stop early.
LenLen() intReturns the number of entries currently in the map.
Range may panic if the callback deletes map entries during iteration. Avoid modifying the map inside the callback.

Stable vs. recency mode

The key’s position is fixed at the time of first insertion. Subsequent Store calls for the same key update the value but leave the order unchanged.
om := orderedmap.NewSlice[string, int](4, true)
om.Store("a", 1)
om.Store("b", 2)
om.Store("c", 3)
om.Store("a", 99) // updates value; "a" stays first

om.Range(func(k string, v int) bool {
    fmt.Println(k, v)
    return true
})
// Output:
// a 99
// b 2
// c 3

Example

The following example inserts eight entries, deletes one, updates another, then iterates over the result in order.
package main

import (
    "fmt"
    "strconv"

    "github.com/fgm/container/orderedmap"
)

func main() {
    const size = 8
    om := orderedmap.NewSlice[string, int](size, true)

    for i := 1; i <= size; i++ {
        om.Store(strconv.Itoa(i), i)
    }

    om.Delete("5")      // remove key "5"
    om.Store("1", 11)   // update key "1"; stable mode keeps it first

    fmt.Printf("Len: %d\n", om.Len())

    om.Range(func(k string, v int) bool {
        fmt.Printf("%s -> %d\n", k, v)
        return true
    })
}
// Output:
// Len: 7
// 1 -> 11
// 2 -> 2
// 3 -> 3
// 4 -> 4
// 6 -> 6
// 7 -> 7
// 8 -> 8

Checking for a key before acting

Load returns a boolean so you can distinguish a missing key from a key that maps to the zero value:
if v, ok := om.Load("mykey"); ok {
    fmt.Println("found:", v)
} else {
    fmt.Println("not present")
}
OrderedMap is not concurrency-safe. If multiple goroutines need to read or write the same map concurrently, add external synchronization (for example, a sync.RWMutex).