Help us shape the future of Go! Take the 2026 Go Developer Survey

maps

package
v0.6.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2026 License: MIT Imports: 5 Imported by: 0

README

maps

import "github.com/gechr/x/maps"

Package maps provides map helpers: sorted iteration, grouping, inversion, and merging.

Index

func Group

func Group[K comparable, V any](seq iter.Seq2[K, V]) map[K][]V

Group collects the pairs of seq into a map of slices, grouping values by key in encounter order.

Example
words := []string{"apple", "banana", "avocado", "blueberry", "cherry"}
byInitial := xmaps.Group(func(yield func(byte, string) bool) {
    for _, w := range words {
        if !yield(w[0], w) {
            return
        }
    }
})
for initial, group := range xmaps.Sorted(byInitial) {
    fmt.Printf("%c: %v\n", initial, group)
}

Output:

a: [apple avocado]
b: [banana blueberry]
c: [cherry]

func GroupFunc

func GroupFunc[K comparable, V any](seq iter.Seq[V], key func(V) K) map[K][]V

GroupFunc collects the values of seq into a map of slices, grouping values in encounter order by the key returned by key.

Example
words := []string{"go", "rust", "zig", "java", "c"}
byLength := xmaps.GroupFunc(slices.Values(words), func(w string) int {
    return len(w)
})
for length, group := range xmaps.Sorted(byLength) {
    fmt.Println(length, group)
}

Output:

1 [c]
2 [go]
3 [zig]
4 [rust java]

func Invert

func Invert[M ~map[K]V, K, V comparable](m M) map[V]K

Invert returns a new map with the keys and values of m swapped. If multiple keys map to the same value, exactly one of them survives as the value in the result, chosen arbitrarily due to map iteration order.

Example
codes := map[string]int{"a": 1, "b": 2, "c": 3}
letters := xmaps.Invert(codes)
for code, letter := range xmaps.Sorted(letters) {
    fmt.Println(code, letter)
}

Output:

1 a
2 b
3 c

func Keys

func Keys[M ~map[K]V, K comparable, V any](m M) []K

Keys returns the keys of m as a slice, in indeterminate order.

Example
m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
keys := xmaps.Keys(m)
slices.Sort(keys)
fmt.Println(strings.Join(keys, ", "))

Output:

alpha, beta, charlie

func KeysNatural

func KeysNatural[M ~map[K]V, K ~string, V any](m M) []K

KeysNatural returns the string keys of m as a slice, sorted in natural order (item2 before item10). See strings.CompareNatural.

Example
m := map[string]int{"item10": 10, "item2": 2, "item1": 1}
fmt.Println(strings.Join(xmaps.KeysNatural(m), ", "))

Output:

item1, item2, item10

func Merge

func Merge[M ~map[K]V, K comparable, V any](ms ...M) M

Merge returns a new map holding the entries of every map in ms. If a key appears in more than one map, the value from the last map wins. The inputs are left unmodified.

Example
defaults := map[string]string{"host": "localhost", "port": "8080"}
overrides := map[string]string{"port": "9090"}
for k, v := range xmaps.Sorted(xmaps.Merge(defaults, overrides)) {
    fmt.Println(k, v)
}

Output:

host localhost
port 9090

func MergeDeep

func MergeDeep[M ~map[K]any, K comparable](ms ...M) M

MergeDeep returns a new map holding the entries of every map in ms, merging nested map[K]any values recursively. If a key appears in more than one map and either value is not a map[K]any, the value from the last map wins. Slices are replaced, not concatenated.

The inputs are left unmodified: every merged level is a new map. Nested maps that appear in only one input are shared with that input, not copied.

Example
defaults := map[string]any{
    "server": map[string]any{"host": "localhost", "port": 8080},
    "debug":  false,
}
overrides := map[string]any{
    "server": map[string]any{"port": 9090},
}
merged := xmaps.MergeDeep(defaults, overrides)
fmt.Println(merged["debug"])
server, _ := merged["server"].(map[string]any)
for k, v := range xmaps.Sorted(server) {
    fmt.Println(k, v)
}

Output:

false
host localhost
port 9090

func MergeFunc

func MergeFunc[M ~map[K]V, K comparable, V any](
    resolve func(k K, existing, incoming V) V,
    ms ...M,
) M

MergeFunc returns a new map holding the entries of every map in ms. If a key appears in more than one map, resolve receives the key, the value merged so far and the incoming value, and returns the value to keep. The inputs are left unmodified.

Example

MergeFunc resolves duplicate keys with a custom function, such as summing the values.

monday := map[string]int{"apples": 3, "pears": 1}
tuesday := map[string]int{"apples": 2, "plums": 5}
sum := func(_ string, existing, incoming int) int { return existing + incoming }
for k, v := range xmaps.Sorted(xmaps.MergeFunc(sum, monday, tuesday)) {
    fmt.Println(k, v)
}

Output:

apples 5
pears 1
plums 5

func Sorted

func Sorted[M ~map[K]V, K cmp.Ordered, V any](m M) iter.Seq2[K, V]

Sorted returns an iterator over the entries of m in ascending key order.

Example
m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
for k, v := range xmaps.Sorted(m) {
    fmt.Println(k, v)
}

Output:

alpha 1
beta 2
charlie 3

func SortedFunc

func SortedFunc[M ~map[K]V, K comparable, V any](m M, compare func(x, y K) int) iter.Seq2[K, V]

SortedFunc returns an iterator over the entries of m in the key order determined by compare, which follows the cmp.Compare convention.

Example

SortedFunc accepts any comparison following the cmp.Compare convention, such as a descending key order.

m := map[int]string{1: "one", 2: "two", 3: "three"}
descending := func(x, y int) int { return cmp.Compare(y, x) }
for k, v := range xmaps.SortedFunc(m, descending) {
    fmt.Println(k, v)
}

Output:

3 three
2 two
1 one

func Values

func Values[M ~map[K]V, K comparable, V any](m M) []V

Values returns the values of m as a slice, in indeterminate order.

Example
m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
values := xmaps.Values(m)
slices.Sort(values)
fmt.Println(values)

Output:

[1 2 3]

func ValuesNatural

func ValuesNatural[M ~map[K]V, K comparable, V ~string](m M) []V

ValuesNatural returns the string values of m as a slice, sorted in natural order (item2 before item10). See strings.CompareNatural.

Example
m := map[int]string{10: "item10", 2: "item2", 1: "item1"}
fmt.Println(strings.Join(xmaps.ValuesNatural(m), ", "))

Output:

item1, item2, item10

Documentation

Overview

Package maps provides map helpers: sorted iteration, grouping, inversion, and merging.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Group

func Group[K comparable, V any](seq iter.Seq2[K, V]) map[K][]V

Group collects the pairs of `seq` into a map of slices, grouping values by key in encounter order.

Example
package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	words := []string{"apple", "banana", "avocado", "blueberry", "cherry"}
	byInitial := xmaps.Group(func(yield func(byte, string) bool) {
		for _, w := range words {
			if !yield(w[0], w) {
				return
			}
		}
	})
	for initial, group := range xmaps.Sorted(byInitial) {
		fmt.Printf("%c: %v\n", initial, group)
	}
}
Output:
a: [apple avocado]
b: [banana blueberry]
c: [cherry]

func GroupFunc

func GroupFunc[K comparable, V any](seq iter.Seq[V], key func(V) K) map[K][]V

GroupFunc collects the values of `seq` into a map of slices, grouping values in encounter order by the key returned by `key`.

Example
package main

import (
	"fmt"
	"slices"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	words := []string{"go", "rust", "zig", "java", "c"}
	byLength := xmaps.GroupFunc(slices.Values(words), func(w string) int {
		return len(w)
	})
	for length, group := range xmaps.Sorted(byLength) {
		fmt.Println(length, group)
	}
}
Output:
1 [c]
2 [go]
3 [zig]
4 [rust java]

func Invert

func Invert[M ~map[K]V, K, V comparable](m M) map[V]K

Invert returns a new map with the keys and values of `m` swapped. If multiple keys map to the same value, exactly one of them survives as the value in the result, chosen arbitrarily due to map iteration order.

Example
package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	codes := map[string]int{"a": 1, "b": 2, "c": 3}
	letters := xmaps.Invert(codes)
	for code, letter := range xmaps.Sorted(letters) {
		fmt.Println(code, letter)
	}
}
Output:
1 a
2 b
3 c

func Keys added in v0.2.18

func Keys[M ~map[K]V, K comparable, V any](m M) []K

Keys returns the keys of `m` as a slice, in indeterminate order.

Example
package main

import (
	"fmt"
	"slices"
	"strings"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
	keys := xmaps.Keys(m)
	slices.Sort(keys)
	fmt.Println(strings.Join(keys, ", "))
}
Output:
alpha, beta, charlie

func KeysNatural added in v0.2.18

func KeysNatural[M ~map[K]V, K ~string, V any](m M) []K

KeysNatural returns the string keys of `m` as a slice, sorted in natural order (`item2` before `item10`). See github.com/gechr/x/strings.CompareNatural.

Example
package main

import (
	"fmt"
	"strings"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[string]int{"item10": 10, "item2": 2, "item1": 1}
	fmt.Println(strings.Join(xmaps.KeysNatural(m), ", "))
}
Output:
item1, item2, item10

func Merge added in v0.6.2

func Merge[M ~map[K]V, K comparable, V any](ms ...M) M

Merge returns a new map holding the entries of every map in `ms`. If a key appears in more than one map, the value from the last map wins. The inputs are left unmodified.

Example
package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	defaults := map[string]string{"host": "localhost", "port": "8080"}
	overrides := map[string]string{"port": "9090"}
	for k, v := range xmaps.Sorted(xmaps.Merge(defaults, overrides)) {
		fmt.Println(k, v)
	}
}
Output:
host localhost
port 9090

func MergeDeep added in v0.6.2

func MergeDeep[M ~map[K]any, K comparable](ms ...M) M

MergeDeep returns a new map holding the entries of every map in `ms`, merging nested `map[K]any` values recursively. If a key appears in more than one map and either value is not a `map[K]any`, the value from the last map wins. Slices are replaced, not concatenated.

The inputs are left unmodified: every merged level is a new map. Nested maps that appear in only one input are shared with that input, not copied.

Example
package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	defaults := map[string]any{
		"server": map[string]any{"host": "localhost", "port": 8080},
		"debug":  false,
	}
	overrides := map[string]any{
		"server": map[string]any{"port": 9090},
	}
	merged := xmaps.MergeDeep(defaults, overrides)
	fmt.Println(merged["debug"])
	server, _ := merged["server"].(map[string]any)
	for k, v := range xmaps.Sorted(server) {
		fmt.Println(k, v)
	}
}
Output:
false
host localhost
port 9090

func MergeFunc added in v0.6.2

func MergeFunc[M ~map[K]V, K comparable, V any](
	resolve func(k K, existing, incoming V) V,
	ms ...M,
) M

MergeFunc returns a new map holding the entries of every map in `ms`. If a key appears in more than one map, `resolve` receives the key, the value merged so far and the incoming value, and returns the value to keep. The inputs are left unmodified.

Example

MergeFunc resolves duplicate keys with a custom function, such as summing the values.

package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	monday := map[string]int{"apples": 3, "pears": 1}
	tuesday := map[string]int{"apples": 2, "plums": 5}
	sum := func(_ string, existing, incoming int) int { return existing + incoming }
	for k, v := range xmaps.Sorted(xmaps.MergeFunc(sum, monday, tuesday)) {
		fmt.Println(k, v)
	}
}
Output:
apples 5
pears 1
plums 5

func Sorted

func Sorted[M ~map[K]V, K cmp.Ordered, V any](m M) iter.Seq2[K, V]

Sorted returns an iterator over the entries of `m` in ascending key order.

Example
package main

import (
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
	for k, v := range xmaps.Sorted(m) {
		fmt.Println(k, v)
	}
}
Output:
alpha 1
beta 2
charlie 3

func SortedFunc

func SortedFunc[M ~map[K]V, K comparable, V any](m M, compare func(x, y K) int) iter.Seq2[K, V]

SortedFunc returns an iterator over the entries of `m` in the key order determined by `compare`, which follows the cmp.Compare convention.

Example

SortedFunc accepts any comparison following the cmp.Compare convention, such as a descending key order.

package main

import (
	"cmp"
	"fmt"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[int]string{1: "one", 2: "two", 3: "three"}
	descending := func(x, y int) int { return cmp.Compare(y, x) }
	for k, v := range xmaps.SortedFunc(m, descending) {
		fmt.Println(k, v)
	}
}
Output:
3 three
2 two
1 one

func Values added in v0.2.18

func Values[M ~map[K]V, K comparable, V any](m M) []V

Values returns the values of `m` as a slice, in indeterminate order.

Example
package main

import (
	"fmt"
	"slices"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[string]int{"charlie": 3, "alpha": 1, "beta": 2}
	values := xmaps.Values(m)
	slices.Sort(values)
	fmt.Println(values)
}
Output:
[1 2 3]

func ValuesNatural added in v0.2.18

func ValuesNatural[M ~map[K]V, K comparable, V ~string](m M) []V

ValuesNatural returns the string values of `m` as a slice, sorted in natural order (`item2` before `item10`). See github.com/gechr/x/strings.CompareNatural.

Example
package main

import (
	"fmt"
	"strings"

	xmaps "github.com/gechr/x/maps"
)

func main() {
	m := map[int]string{10: "item10", 2: "item2", 1: "item1"}
	fmt.Println(strings.Join(xmaps.ValuesNatural(m), ", "))
}
Output:
item1, item2, item10

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL