github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/snm/snm.go (about)

     1  // Package snm provides convenience functions for slices and maps.
     2  package snm
     3  
     4  import (
     5  	"cmp"
     6  	"slices"
     7  
     8  	"golang.org/x/exp/constraints"
     9  	"golang.org/x/exp/maps"
    10  )
    11  
    12  // Slice returns a new slice of size n whose values are the results
    13  // of applying f on each index.
    14  func Slice[T any](n int, f func(int) T) []T {
    15  	s := make([]T, n)
    16  	for i := range s {
    17  		s[i] = f(i)
    18  	}
    19  	return s
    20  }
    21  
    22  // SliceToSlice returns a slice of the same length containing the results
    23  // of applying f to the elements of s.
    24  func SliceToSlice[A any, B any](a []A, f func(A) B) []B {
    25  	b := make([]B, len(a))
    26  	for i := range a {
    27  		b[i] = f(a[i])
    28  	}
    29  	return b
    30  }
    31  
    32  // MapToMap returns a map containing the results of applying f to the key-value
    33  // pairs of m.
    34  // f should return a new key-value pair for the new map.
    35  // Keys that appear more than once will override each other.
    36  func MapToMap[K comparable, V any, K2 comparable, V2 any](
    37  	m map[K]V, f func(K, V) (K2, V2)) map[K2]V2 {
    38  	mm := make(map[K2]V2, len(m))
    39  	for k, v := range m {
    40  		k2, v2 := f(k, v)
    41  		mm[k2] = v2
    42  	}
    43  	return mm
    44  }
    45  
    46  // FilterSlice returns a new slice containing only the elements
    47  // for which keep returns true.
    48  func FilterSlice[S any](s []S, keep func(S) bool) []S {
    49  	var result []S
    50  	for _, e := range s {
    51  		if keep(e) {
    52  			result = append(result, e)
    53  		}
    54  	}
    55  	return result
    56  }
    57  
    58  // FilterMap returns a new map containing only the elements
    59  // for which keep returns true.
    60  func FilterMap[K comparable, V any](m map[K]V, keep func(k K, v V) bool) map[K]V {
    61  	mm := map[K]V{}
    62  	for k, v := range m {
    63  		if keep(k, v) {
    64  			mm[k] = v
    65  		}
    66  	}
    67  	return mm
    68  }
    69  
    70  // Sorted sorts the input and returns it.
    71  func Sorted[T constraints.Ordered](s []T) []T {
    72  	slices.Sort(s)
    73  	return s
    74  }
    75  
    76  // SortedFunc sorts the input and returns it.
    77  func SortedFunc[T any](s []T, cmp func(T, T) int) []T {
    78  	slices.SortFunc(s, cmp)
    79  	return s
    80  }
    81  
    82  // At returns the elements of t at the indexes in at.
    83  func At[T any, I constraints.Integer](t []T, at []I) []T {
    84  	result := make([]T, 0, len(at))
    85  	for _, i := range at {
    86  		result = append(result, t[i])
    87  	}
    88  	return result
    89  }
    90  
    91  // DefaultMap wraps a map with a function that generates values for missing keys.
    92  type DefaultMap[K comparable, V any] struct {
    93  	M map[K]V   // Underlying map. Can be safely read from and written to.
    94  	F func(K) V // Generator function.
    95  }
    96  
    97  // Get returns the value associated with key k.
    98  // If k is missing from the map, the generator function is called with k and the
    99  // result becomes k's value.
   100  func (m DefaultMap[K, V]) Get(k K) V {
   101  	if v, ok := m.M[k]; ok {
   102  		return v
   103  	}
   104  	v := m.F(k)
   105  	m.M[k] = v
   106  	return v
   107  }
   108  
   109  // Set sets v as k's value.
   110  func (m DefaultMap[K, V]) Set(k K, v V) {
   111  	m.M[k] = v
   112  }
   113  
   114  // NewDefaultMap returns an empty map with the given function as the missing
   115  // value generator.
   116  func NewDefaultMap[K comparable, V any](f func(K) V) DefaultMap[K, V] {
   117  	return DefaultMap[K, V]{map[K]V{}, f}
   118  }
   119  
   120  // Compare is a generic comparator function for ordered types.
   121  //
   122  // Deprecated: use [cmp.Compare] instead.
   123  func Compare[T constraints.Ordered](a, b T) int {
   124  	if a < b {
   125  		return -1
   126  	}
   127  	if a > b {
   128  		return 1
   129  	}
   130  	return 0
   131  }
   132  
   133  // CompareReverse orders values from big to small.
   134  // Should be generally used as a parameter, not called.
   135  func CompareReverse[T constraints.Ordered](a, b T) int {
   136  	return -1 * cmp.Compare(a, b)
   137  }
   138  
   139  // SortedKeys sorts a map's keys according to their values' natural order.
   140  func SortedKeys[K comparable, V constraints.Ordered](
   141  	m map[K]V) []K {
   142  	return SortedFunc(maps.Keys(m), func(a, b K) int {
   143  		return Compare(m[a], m[b])
   144  	})
   145  }
   146  
   147  // SortedKeysFunc sorts a map's keys by comparing their values.
   148  func SortedKeysFunc[K comparable, V constraints.Ordered](
   149  	m map[K]V, cmp func(V, V) int) []K {
   150  	return SortedFunc(maps.Keys(m), func(a, b K) int {
   151  		return cmp(m[a], m[b])
   152  	})
   153  }
   154  
   155  // Number is an integer or a float.
   156  type Number interface {
   157  	constraints.Integer | constraints.Float
   158  }
   159  
   160  // Cast casts each element in the slice.
   161  func Cast[TO Number, FROM Number](s []FROM) []TO {
   162  	return SliceToSlice(s, func(x FROM) TO { return TO(x) })
   163  }