go-ordered-map

repository·master·Indexed 20 days ago

https://github.com/wk8/go-ordered-map

A high-performance, generic-supported ordered map implementation for Go that preserves insertion order, similar to Python's OrderedDict. It supports JSON and YAML serialization, manual pointer-based iteration, and native Go 1.23 iterators. The library provides an idiomatic API for managing key-value pairs, including methods for reordering elements, filtering, and initializing with capacity hints or initial data.

Tokens
4K
Snippets
18
Records
20
Agent score
69%

What's inside go-ordered-map

  1. Iterate through an OrderedMap

    master

    You can iterate through the map in several ways depending on your Go version and desired direction.

    Manual Iteration (Pointer-based)

    For all Go versions, you can use Oldest() and Newest() to get a pointer to the first/last pair. Use .Next() to move forward or .Prev() to move backward. This is efficient as it allows breaking early without full traversal.

    Native Iterator Support (Go >= 1.23)

    If you are using Go 1.23 or later, you can use the range keyword with the following methods:

    • FromOldest(): Iterates pairs from oldest to newest.
    • FromNewest(): Iterates pairs from newest to oldest.
    • KeysFromOldest() / KeysFromNewest(): Iterates only the keys.
    • ValuesFromOldest() / ValuesFromNewest(): Iterates only the values.
    // Manual iteration (Oldest to Newest)
    for pair := om.Oldest(); pair != nil; pair = pair.Next() {
        fmt.Println(pair.Key, pair.Value)
    }
    
    // Manual iteration (Newest to Oldest)
    for pair := om.Newest(); pair != nil; pair = pair.Prev() {
        fmt.Println(pair.Key, pair.Value)
    }
    
    // Go 1.23+ range syntax
    for k, v := range om.FromOldest() {
        fmt.Println(k, v)
    }
  2. Choose the correct version based on your Go version

    master

    The library version requirements are as follows:

    • Go >= 1.23: Use version >= 2.2.0 to access generics and native iterators.
    • Go < 1.23: Use version 2.1.8.
    • Go < 1.18: Use version 1 (which uses interface{} instead of generics).
  3. Initialize an OrderedMap

    master

    You can create a new OrderedMap using orderedmap.New[K, V](). Keys must implement the comparable constraint. You can also provide a capacity hint or initial data.

    With capacity hint

    Pass an integer to New to provide a capacity hint, similar to make(map[K]V, capacity).

    With initial data

    Use orderedmap.WithInitialData to populate the map during initialization. This requires passing orderedmap.Pair[K, V] objects.

    // Capacity hint
    om := orderedmap.New[int, *myStruct](28)
    
    // Initial data
    om := orderedmap.New[int, string](orderedmap.WithInitialData[int, string](
    	orderedmap.Pair[int, string]{Key: 12, Value: "foo"},
    	orderedmap.Pair[int, string]{Key: 28, Value: "bar"},
    ))
  4. Serialize and Deserialize OrderedMaps (JSON/YAML)

    master

    The OrderedMap supports JSON and YAML marshalling/unmarshalling while preserving the insertion order.

    // JSON
    data, err := json.Marshal(om)
    err = json.Unmarshal(data, &om)
    
    // YAML (requires yaml.v3)
    data, err := yaml.Marshal(om)
    err = yaml.Unmarshal(data, &om)
  5. Perform basic Map operations

    master

    The OrderedMap provides an idiomatic API for managing key-value pairs:

    • Set(key, value): Inserts or updates a key.
    • Get(key): Returns the value and a boolean indicating if the key was present.
    • Filter(func(key, value) bool): Removes all pairs that do not satisfy the provided predicate function.
    om := orderedmap.New[string, string]()
    
    om.Set("foo", "bar")
    
    val, ok := om.Get("foo") // val="bar", ok=true
    
    om.Filter(func(k, v string) bool {
        return strings.Contains(k, "o")
    })
  6. Create an OrderedMap from an iterator

    master

    The orderedmap.From(iterator) function allows you to create a new OrderedMap instance from an existing iterator (such as those returned by FromOldest() or FromNewest()).

    // Create a new map from the oldest elements of an existing map
    om2 := orderedmap.From(om.FromOldest())
  7. Reorder elements in OrderedMap

    master

    You can change the insertion order of existing keys using the following methods. These methods return a KeyNotFoundError[K] if either the key or the markKey is not present in the map.

    • MoveAfter(key, markKey K) error: Moves key to the position immediately after markKey.
    • MoveBefore(key, markKey K) error: Moves key to the position immediately before markKey.
    • MoveToBack(key K) error: Moves key to the end of the map (making it the newest element).
    • MoveToFront(key K) error: Moves key to the beginning of the map (making it the oldest element).
    • GetAndMoveToBack(key K) (V, error): Retrieves the value and moves the key to the back in one operation.
    • GetAndMoveToFront(key K) (V, error): Retrieves the value and moves the key to the front in one operation.
    // Move a key to the very end
    err := om.MoveToBack("important_key")
    if err != nil {
        // handle error
    }
    
    // Move key A to be right after key B
    err = om.MoveAfter("keyA", "keyB")
  8. Unmarshal YAML into an OrderedMap

    master

    The OrderedMap[K, V] type implements the yaml.Unmarshaler interface. You can unmarshal a YAML mapping directly into an OrderedMap.

    Requirements & Behavior:

    • The input YAML must be a mapping (yaml.MappingNode). If the input is not a mapping, an error is returned.
    • The keys and values in the YAML must be compatible with the types K and V defined for the OrderedMap.
    • The OrderedMap will be populated using the Set(key, value) method, which maintains the order found in the YAML source.
    var om orderedmap.OrderedMap[string, int]
    err := yaml.Unmarshal(yamlBytes, &om)
  9. Marshal OrderedMap to YAML

    master

    The OrderedMap[K, V] type implements the yaml.Marshaler interface. When marshaling an OrderedMap to YAML, it preserves the insertion order of the elements by iterating through the map using the Oldest() iterator. If the OrderedMap is nil, it marshals to a YAML null value.

    // Assuming om is an *orderedmap.OrderedMap[string, int]
    // and you are using gopkg.in/yaml.v3
    data, err := yaml.Marshal(om)
  10. Initialize an OrderedMap with New()

    master

    Use orderedmap.New[K, V](options ...any) to create a new ordered map. The options parameter is flexible and supports several ways to configure the map:

    1. Capacity Hint: Pass a single int to set the initial capacity, similar to make(map[K]V, capacity).
    2. InitOptions: Pass one or more InitOption[K, V] functions.
    3. Boolean: Pass a single bool to set the disableHTMLEscape flag.

    Note: If you provide more than one option and they are not InitOption types (e.g., providing both an int and a bool), the function will panic.

    // Using capacity hint
    om := orderedmap.New[string, int](10)
    
    // Using InitOptions
    om := orderedmap.New[string, int](
        orderedmap.WithCapacity(10),
        orderedmap.WithInitialData(orderedmap.Pair[string, int]{Key: "a", Value: 1}),
        orderedmap.WithDisableHTMLEscape(),
    )
  11. Filter elements in OrderedMap

    master

    The Filter(predicate func(K, V) bool) method removes elements from the map that do not satisfy the provided predicate function. The iteration happens from oldest to newest.

    // Remove all entries where the value is less than 10
    om.Filter(func(k string, v int) bool {
        return v >= 10
    })