180 lines
3.8 KiB
Go
180 lines
3.8 KiB
Go
package mapsx
|
|
|
|
import (
|
|
"cmp"
|
|
"iter"
|
|
"slices"
|
|
)
|
|
|
|
/*
|
|
Get mimics Python's [dict.get()] behavior, returning value `v` if key `k`
|
|
is not found in map `m`.
|
|
|
|
See also [GetOk], [Must].
|
|
|
|
[dict.get()]: https://docs.python.org/3/library/stdtypes.html#dict.get
|
|
*/
|
|
func Get[Map ~map[K]V, K comparable, V any](m Map, k K, v V) (val V) {
|
|
|
|
val, _ = GetOk(m, k, v)
|
|
|
|
return
|
|
}
|
|
|
|
// GetOk is like [Get] but also explicitly indicates whether `k` was found or not. See also [Must].
|
|
func GetOk[Map ~map[K]V, K comparable, V any](m Map, k K, v V) (val V, found bool) {
|
|
|
|
if val, found = m[k]; !found {
|
|
val = v
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
ListKeys returns map `m`'s keys as a slice (unlike [maps.Keys],
|
|
which returns an iterator via [iter.Seq]).
|
|
|
|
ListKeys will return nil if `m` is nil, and an empty slice
|
|
if `m` is non-nil but empty.
|
|
|
|
The ordering of `mapKeys` is unpredictable as maps are unsorted
|
|
and no explicit sorting is performed.
|
|
See [SortedKeys] and [ListSortedKeys] if sorting is desired.
|
|
*/
|
|
func ListKeys[Map ~map[K]V, K comparable, V any](m Map) (mapKeys []K) {
|
|
|
|
var k K
|
|
|
|
if m == nil {
|
|
return
|
|
}
|
|
mapKeys = make([]K, 0, len(m))
|
|
|
|
for k, _ = range m {
|
|
mapKeys = append(mapKeys, k)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
ListSortedKeys is like [ListKeys] but returns the keys in a sorted slice.
|
|
|
|
The keys in map `m` MUST conform to a [cmp.Ordered]!
|
|
*/
|
|
func ListSortedKeys[Map ~map[K]V, K cmp.Ordered, V any](m Map) (mapKeys []K) {
|
|
|
|
// All cmp.Ordered types are comparable, but not all comparable types are cmp.Ordered.
|
|
mapKeys = ListKeys(m)
|
|
|
|
slices.Sort(mapKeys)
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
ListSortedValues is like [ListValues] but returns the values in a sorted slice.
|
|
|
|
The values in map `m` MUST conform to a [cmp.Ordered]!
|
|
*/
|
|
func ListSortedValues[Map ~map[K]V, K comparable, V cmp.Ordered](m Map) (mapVals []V) {
|
|
|
|
// All cmp.Ordered types are comparable, but not all comparable types are cmp.Ordered.
|
|
mapVals = ListValues(m)
|
|
|
|
slices.Sort(mapVals)
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
ListValues returns map `m`'s values as a slice (unlike [maps.Values],
|
|
which returns an iterator via [iter.Seq]).
|
|
|
|
ListValues will return nil if `m` is nil, and an empty slice
|
|
if `m` is non-nil but empty.
|
|
|
|
The ordering of `mapVals` is unpredictable as maps are unsorted
|
|
and no explicit sorting is performed.
|
|
See [SortedValues] and [ListSortedValues] if sorting is desired.
|
|
*/
|
|
func ListValues[Map ~map[K]V, K comparable, V any](m Map) (mapVals []V) {
|
|
|
|
var v V
|
|
|
|
if m == nil {
|
|
return
|
|
}
|
|
mapVals = make([]V, 0, len(m))
|
|
|
|
for _, v = range m {
|
|
mapVals = append(mapVals, v)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
SortedKeys is like [maps.Keys] but will sort the keys in the returned [iter.Seq].
|
|
(There is a small cost to this.)
|
|
|
|
The keys in map `m` MUST conform to a [cmp.Ordered]!
|
|
*/
|
|
func SortedKeys[Map ~map[K]V, K cmp.Ordered, V any](m Map) (mapKeys iter.Seq[K]) {
|
|
|
|
var k K
|
|
// All cmp.Ordered types are comparable, but not all comparable types are cmp.Ordered.
|
|
var keys []K = ListKeys(m)
|
|
|
|
slices.Sort(keys)
|
|
|
|
return func(yield func(K) bool) {
|
|
for _, k = range keys {
|
|
if !yield(k) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
SortedValues is like [maps.Values] but will sort the values in the returned [iter.Seq].
|
|
(There is a small cost to this.)
|
|
|
|
The values in map `m` MUST conform to a [cmp.Ordered]!
|
|
*/
|
|
func SortedValues[Map ~map[K]V, K comparable, V cmp.Ordered](m Map) (mapVals iter.Seq[V]) {
|
|
|
|
var v V
|
|
// All cmp.Ordered types are comparable, but not all comparable types are cmp.Ordered.
|
|
var vals []V = ListValues(m)
|
|
|
|
slices.Sort(vals)
|
|
|
|
return func(yield func(V) bool) {
|
|
for _, v = range vals {
|
|
if !yield(v) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
Must, unlike [Get] or [GetOk], requires that `k` be in map `m`.
|
|
|
|
A panic with error [ErrNotFound] will be raised if `k` is not present.
|
|
Otherwise the found value will be returned.
|
|
*/
|
|
func Must[Map ~map[K]V, K comparable, V any](m Map, k K) (val V) {
|
|
|
|
var ok bool
|
|
|
|
if val, ok = m[k]; !ok {
|
|
panic(ErrNotFound)
|
|
}
|
|
|
|
return
|
|
}
|