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 }