github.com/m4gshm/gollections@v0.0.10/map_/api.go (about)

     1  // Package map_ provides map processing helper functions
     2  package map_
     3  
     4  import (
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/m4gshm/gollections/c"
     9  	"github.com/m4gshm/gollections/convert/as"
    10  	"github.com/m4gshm/gollections/kv"
    11  	"github.com/m4gshm/gollections/map_/resolv"
    12  )
    13  
    14  // ErrBreak is For, Track breaker
    15  var ErrBreak = c.ErrBreak
    16  
    17  // Of instantiates a ap from the specified key/value pairs
    18  func Of[K comparable, V any](elements ...c.KV[K, V]) map[K]V {
    19  	var (
    20  		uniques = make(map[K]V, len(elements))
    21  	)
    22  	for _, kv := range elements {
    23  		key := kv.Key()
    24  		val := kv.Value()
    25  		uniques[key] = val
    26  	}
    27  	return uniques
    28  }
    29  
    30  // OfLoop builds a map by iterating key\value pairs of a source.
    31  // The hasNext specifies a predicate that tests existing of a next pair in the source.
    32  // The getNext extracts the pair.
    33  func OfLoop[S any, K comparable, V any](source S, hasNext func(S) bool, getNext func(S) (K, V, error)) (map[K]V, error) {
    34  	return OfLoopResolv(source, hasNext, getNext, resolv.First[K, V])
    35  }
    36  
    37  // OfLoopResolv builds a map by iterating elements of a source.
    38  // The hasNext specifies a predicate that tests existing of a next pair in the source.
    39  // The getNext extracts the element.
    40  // The resolv values for duplicated keys.
    41  func OfLoopResolv[S any, K comparable, E, V any](source S, hasNext func(S) bool, getNext func(S) (K, E, error), resolv func(bool, K, V, E) V) (map[K]V, error) {
    42  	r := map[K]V{}
    43  	for hasNext(source) {
    44  		k, elem, err := getNext(source)
    45  		if err != nil {
    46  			return r, err
    47  		}
    48  		existVal, ok := r[k]
    49  		r[k] = resolv(ok, k, existVal, elem)
    50  	}
    51  	return r, nil
    52  }
    53  
    54  // GroupOfLoop builds a map of slices by iterating over elements, extracting key\value pairs and grouping the values for each key in the slices.
    55  // The hasNext specifies a predicate that tests existing of a next pair in the source.
    56  // The getNext extracts the pair.
    57  func GroupOfLoop[S any, K comparable, V any](source S, hasNext func(S) bool, getNext func(S) (K, V, error)) (map[K][]V, error) {
    58  	return OfLoopResolv(source, hasNext, getNext, func(exists bool, key K, elements []V, val V) []V {
    59  		return append(elements, val)
    60  	})
    61  }
    62  
    63  // Generate builds a map by an generator function.
    64  // The next returns a key\value pair, or false if the generation is over, or an error.
    65  func Generate[K comparable, V any](next func() (K, V, bool, error)) (map[K]V, error) {
    66  	return GenerateResolv(next, resolv.First[K, V])
    67  }
    68  
    69  // GenerateResolv builds a map by an generator function.
    70  // The next returns a key\value pair, or false if the generation is over, or an error.
    71  // The resolv selects value for duplicated keys.
    72  func GenerateResolv[K comparable, V any](next func() (K, V, bool, error), resolv func(bool, K, V, V) V) (map[K]V, error) {
    73  	r := map[K]V{}
    74  	for {
    75  		k, v, ok, err := next()
    76  		if err != nil || !ok {
    77  			return r, err
    78  		}
    79  		ov, ok := r[k]
    80  		r[k] = resolv(ok, k, ov, v)
    81  	}
    82  }
    83  
    84  // Clone makes a copy of the 'elements' map. The values are copied as is.
    85  func Clone[M ~map[K]V, K comparable, V any](elements M) M {
    86  	return DeepClone(elements, as.Is[V])
    87  }
    88  
    89  // DeepClone makes a copy of the 'elements' map. The values are copied by the 'copier' function
    90  func DeepClone[M ~map[K]V, K comparable, V any](elements M, copier func(V) V) M {
    91  	return ConvertValues(elements, copier)
    92  }
    93  
    94  // ConvertValues creates a map with converted values
    95  func ConvertValues[M ~map[K]V, V, Vto any, K comparable](elements M, by func(V) Vto) map[K]Vto {
    96  	return Convert(elements, as.Is[K], by)
    97  }
    98  
    99  // ConvertKeys creates a map with converted keys
   100  func ConvertKeys[M ~map[K]V, K, Kto comparable, V any](elements M, by func(K) Kto) map[Kto]V {
   101  	return Convert(elements, by, as.Is[V])
   102  }
   103  
   104  // Convert creates a map with converted keys and values
   105  func Convert[M ~map[K]V, K, Kto comparable, V, Vto any](elements M, keyConverter func(K) Kto, valConverter func(V) Vto) map[Kto]Vto {
   106  	converted := make(map[Kto]Vto, len(elements))
   107  	for key, val := range elements {
   108  		converted[keyConverter(key)] = valConverter(val)
   109  	}
   110  	return converted
   111  }
   112  
   113  // Conv creates a map with converted keys and values
   114  func Conv[M ~map[K]V, K, Kto comparable, V, Vto any](elements M, keyConverter func(K) (Kto, error), valConverter func(V) (Vto, error)) (map[Kto]Vto, error) {
   115  	converted := make(map[Kto]Vto, len(elements))
   116  	for key, val := range elements {
   117  		kto, err := keyConverter(key)
   118  		if err != nil {
   119  			return converted, err
   120  		}
   121  		vto, err := valConverter(val)
   122  		if err != nil {
   123  			return converted, err
   124  		}
   125  		converted[kto] = vto
   126  	}
   127  	return converted, nil
   128  }
   129  
   130  // Filter creates a map containing only the filtered elements
   131  func Filter[M ~map[K]V, K comparable, V any](elements M, filter func(K, V) bool) map[K]V {
   132  	filtered := map[K]V{}
   133  	for key, val := range elements {
   134  		if filter(key, val) {
   135  			filtered[key] = val
   136  		}
   137  	}
   138  	return filtered
   139  }
   140  
   141  // FilterKeys creates a map containing only the filtered elements
   142  func FilterKeys[M ~map[K]V, K comparable, V any](elements M, filter func(K) bool) map[K]V {
   143  	filtered := map[K]V{}
   144  	for key, val := range elements {
   145  		if filter(key) {
   146  			filtered[key] = val
   147  		}
   148  	}
   149  	return filtered
   150  }
   151  
   152  // FilterValues creates a map containing only the filtered elements
   153  func FilterValues[M ~map[K]V, K comparable, V any](elements M, filter func(V) bool) map[K]V {
   154  	filtered := map[K]V{}
   155  	for key, val := range elements {
   156  		if filter(val) {
   157  			filtered[key] = val
   158  		}
   159  	}
   160  	return filtered
   161  }
   162  
   163  // Keys returns keys of the 'elements' map as a slice
   164  func Keys[M ~map[K]V, K comparable, V any](elements M) []K {
   165  	if elements == nil {
   166  		return nil
   167  	}
   168  	return AppendKeys(elements, make([]K, 0, len(elements)))
   169  }
   170  
   171  // AppendKeys collects keys of the specified 'elements' map into the specified 'out' slice
   172  func AppendKeys[M ~map[K]V, K comparable, V any](elements M, out []K) []K {
   173  	for key := range elements {
   174  		out = append(out, key)
   175  	}
   176  	return out
   177  }
   178  
   179  // Values returns values of the 'elements' map as a slice
   180  func Values[M ~map[K]V, K comparable, V any](elements M) []V {
   181  	if elements == nil {
   182  		return nil
   183  	}
   184  	return AppendValues(elements, make([]V, 0, len(elements)))
   185  }
   186  
   187  // AppendValues collects values of the specified 'elements' map into the specified 'out' slice
   188  func AppendValues[M ~map[K]V, K comparable, V any](elements M, out []V) []V {
   189  	for _, val := range elements {
   190  		out = append(out, val)
   191  	}
   192  	return out
   193  }
   194  
   195  // ValuesConverted makes a slice of converted map values
   196  func ValuesConverted[M ~map[K]V, K comparable, V, Vto any](elements M, by func(V) Vto) []Vto {
   197  	values := make([]Vto, 0, len(elements))
   198  	for _, val := range elements {
   199  		values = append(values, by(val))
   200  	}
   201  	return values
   202  }
   203  
   204  // Track applies the 'tracker' function for every key/value pairs from the 'elements' map. Return the c.ErrBreak to stop
   205  func Track[M ~map[K]V, K comparable, V any](elements M, tracker func(K, V) error) error {
   206  	for key, val := range elements {
   207  		if err := tracker(key, val); err == ErrBreak {
   208  			return nil
   209  		} else if err != nil {
   210  			return err
   211  		}
   212  	}
   213  	return nil
   214  }
   215  
   216  // TrackEach applies the 'tracker' function for every key/value pairs from the 'elements' map
   217  func TrackEach[M ~map[K]V, K comparable, V any](elements M, tracker func(K, V)) {
   218  	for key, val := range elements {
   219  		tracker(key, val)
   220  	}
   221  }
   222  
   223  // For applies the 'walker' function for key/value pairs from the elements. Return the c.ErrBreak to stop.
   224  func For[M ~map[K]V, K comparable, V any](elements M, walker func(c.KV[K, V]) error) error {
   225  	for key, val := range elements {
   226  		if err := walker(kv.New(key, val)); err == ErrBreak {
   227  			return nil
   228  		} else if err != nil {
   229  			return err
   230  		}
   231  	}
   232  	return nil
   233  }
   234  
   235  // ForEach applies the 'walker' function for every key/value pair from the elements map
   236  func ForEach[M ~map[K]V, K comparable, V any](elements M, walker func(c.KV[K, V])) {
   237  	for key, val := range elements {
   238  		walker(kv.New(key, val))
   239  	}
   240  }
   241  
   242  // TrackOrdered applies the 'tracker' function for key/value pairs from the 'elements' map in order of the 'order' slice. Return the c.ErrBreak to stop
   243  func TrackOrdered[M ~map[K]V, K comparable, V any](order []K, elements M, tracker func(K, V) error) error {
   244  	for _, key := range order {
   245  		if err := tracker(key, elements[key]); err == ErrBreak {
   246  			return nil
   247  		} else if err != nil {
   248  			return err
   249  		}
   250  	}
   251  	return nil
   252  }
   253  
   254  // TrackEachOrdered applies the 'tracker' function for evey key/value pair from the 'elements' map in order of the 'order' slice
   255  func TrackEachOrdered[M ~map[K]V, K comparable, V any](order []K, uniques M, tracker func(K, V)) {
   256  	for _, key := range order {
   257  		tracker(key, uniques[key])
   258  	}
   259  }
   260  
   261  // ForOrdered applies the 'walker' function for every key/value pair from the 'elements' map in order of the 'order' slice. Return the c.ErrBreak to stop.
   262  func ForOrdered[M ~map[K]V, K comparable, V any](order []K, elements M, walker func(c.KV[K, V]) error) error {
   263  	for _, key := range order {
   264  		if err := walker(kv.New(key, elements[key])); err == ErrBreak {
   265  			return nil
   266  		} else if err != nil {
   267  			return err
   268  		}
   269  	}
   270  	return nil
   271  }
   272  
   273  // ForEachOrdered applies the 'walker' function for every key/value pair from the 'elements' map in order of the 'order' slice.
   274  func ForEachOrdered[M ~map[K]V, K comparable, V any](order []K, elements M, walker func(c.KV[K, V])) {
   275  	for _, key := range order {
   276  		walker(kv.New(key, elements[key]))
   277  	}
   278  }
   279  
   280  // ForKeys applies the 'walker' function for keys from the 'elements' map . Return the c.ErrBreak to stop.
   281  func ForKeys[M ~map[K]V, K comparable, V any](elements M, walker func(K) error) error {
   282  	for key := range elements {
   283  		if err := walker(key); err == ErrBreak {
   284  			return nil
   285  		} else if err != nil {
   286  			return err
   287  		}
   288  	}
   289  	return nil
   290  }
   291  
   292  // ForEachKey applies the 'walker' function for every key from from the 'elements' map
   293  func ForEachKey[M ~map[K]V, K comparable, V any](elements M, walker func(K)) {
   294  	for key := range elements {
   295  		walker(key)
   296  	}
   297  }
   298  
   299  // ForValues applies the 'walker' function for values from the 'elements' map . Return the c.ErrBreak to stop..
   300  func ForValues[M ~map[K]V, K comparable, V any](elements M, walker func(V) error) error {
   301  	for _, val := range elements {
   302  		if err := walker(val); err == ErrBreak {
   303  			return nil
   304  		} else if err != nil {
   305  			return err
   306  		}
   307  	}
   308  	return nil
   309  }
   310  
   311  // ForEachValue applies the 'walker' function for every value from from the 'elements' map
   312  func ForEachValue[M ~map[K]V, K comparable, V any](elements M, walker func(V)) {
   313  	for _, val := range elements {
   314  		walker(val)
   315  	}
   316  }
   317  
   318  // ForOrderedValues applies the 'walker' function for values from the 'elements' map in order of the 'order' slice. Return the c.ErrBreak to stop..
   319  func ForOrderedValues[M ~map[K]V, K comparable, V any](order []K, elements M, walker func(V) error) error {
   320  	for _, key := range order {
   321  		val := elements[key]
   322  		if err := walker(val); err == ErrBreak {
   323  			return nil
   324  		} else if err != nil {
   325  			return err
   326  		}
   327  	}
   328  	return nil
   329  }
   330  
   331  // ForEachOrderedValues applies the 'walker' function for each value from the 'elements' map in order of the 'order' slice
   332  func ForEachOrderedValues[M ~map[K]V, K comparable, V any](order []K, elements M, walker func(V)) {
   333  	for _, key := range order {
   334  		val := elements[key]
   335  		walker(val)
   336  	}
   337  }
   338  
   339  // ToStringOrdered converts elements to the string representation according to the order
   340  func ToStringOrdered[M ~map[K]V, K comparable, V any](order []K, elements M) string {
   341  	return ToStringOrderedf(order, elements, "%+v:%+v", " ")
   342  }
   343  
   344  // ToStringOrderedf converts elements to a string representation using a key/value pair format and a delimeter. In order
   345  func ToStringOrderedf[M ~map[K]V, K comparable, V any](order []K, elements M, kvFormat, delim string) string {
   346  	str := strings.Builder{}
   347  	str.WriteString("[")
   348  	for i, K := range order {
   349  		if i > 0 {
   350  			_, _ = str.WriteString(delim)
   351  		}
   352  		str.WriteString(fmt.Sprintf(kvFormat, K, elements[K]))
   353  	}
   354  	str.WriteString("]")
   355  	return str.String()
   356  }
   357  
   358  // ToString converts elements to the string representation
   359  func ToString[M ~map[K]V, K comparable, V any](elements M) string {
   360  	return ToStringf(elements, "%+V:%+V", " ")
   361  }
   362  
   363  // ToStringf converts elements to a string representation using a key/value pair format and a delimeter
   364  func ToStringf[M ~map[K]V, K comparable, V any](elements M, kvFormat, delim string) string {
   365  	str := strings.Builder{}
   366  	str.WriteString("[")
   367  	i := 0
   368  	for K, V := range elements {
   369  		if i > 0 {
   370  			_, _ = str.WriteString(delim)
   371  		}
   372  		str.WriteString(fmt.Sprintf(kvFormat, K, V))
   373  		i++
   374  	}
   375  	str.WriteString("]")
   376  	return str.String()
   377  }
   378  
   379  // Reduce reduces the key/value pairs by the 'next' function into an one pair using the 'merge' function
   380  func Reduce[M ~map[K]V, K comparable, V any](elements M, merge func(K, K, V, V) (K, V)) (rk K, rv V) {
   381  	first := true
   382  	for k, v := range elements {
   383  		if first {
   384  			rk, rv = k, v
   385  			first = false
   386  		} else {
   387  			rk, rv = merge(rk, k, rv, v)
   388  		}
   389  	}
   390  	return rk, rv
   391  }
   392  
   393  // HasAny finds the first key/value pair that satisfies the 'predicate' function condition and returns true if successful
   394  func HasAny[M ~map[K]V, K comparable, V any](elements M, predicate func(K, V) bool) bool {
   395  	for k, v := range elements {
   396  		if predicate(k, v) {
   397  			return true
   398  		}
   399  	}
   400  	return false
   401  }
   402  
   403  // ToSlice collects key\value elements to a slice by applying the specified converter to evety element
   404  func ToSlice[M ~map[K]V, K comparable, V any, T any](elements M, converter func(key K, val V) T) []T {
   405  	out := make([]T, 0, len(elements))
   406  	for key, val := range elements {
   407  		out = append(out, converter(key, val))
   408  	}
   409  	return out
   410  }
   411  
   412  // ToSlicee collects key\value elements to a slice by applying the specified erroreable converter to evety element
   413  func ToSlicee[M ~map[K]V, K comparable, V any, T any](elements M, converter func(key K, val V) (T, error)) ([]T, error) {
   414  	out := make([]T, 0, len(elements))
   415  	for key, val := range elements {
   416  		t, err := converter(key, val)
   417  		if err != nil {
   418  			return out, err
   419  		}
   420  		out = append(out, t)
   421  	}
   422  	return out, nil
   423  }
   424  
   425  // Empty checks the val map is empty
   426  func Empty[M ~map[K]V, K comparable, V any](val M) bool {
   427  	return len(val) == 0
   428  }
   429  
   430  // NotEmpty checks the val map is not empty
   431  func NotEmpty[M ~map[K]V, K comparable, V any](val M) bool {
   432  	return !Empty(val)
   433  }
   434  
   435  // Get returns the value by the specified key from the map m or zero if the map doesn't contain that key
   436  func Get[M ~map[K]V, K comparable, V any](m M, key K) V {
   437  	val, _ := GetOk(m, key)
   438  	return val
   439  }
   440  
   441  // GetOk returns the value, and true by the specified key from the map m or zero and false if the map doesn't contain that key
   442  func GetOk[M ~map[K]V, K comparable, V any](m M, key K) (val V, ok bool) {
   443  	if m != nil {
   444  		val, ok = m[key]
   445  	}
   446  	return val, ok
   447  }
   448  
   449  // Getter creates a function that can be used for retrieving a value from the map m by a key
   450  func Getter[M ~map[K]V, K comparable, V any](m M) func(key K) V {
   451  	return func(key K) V { return Get(m, key) }
   452  }
   453  
   454  // GetterOk creates a function that can be used for retrieving a value from the map m by a key
   455  func GetterOk[M ~map[K]V, K comparable, V any](m M) func(key K) (V, bool) {
   456  	return func(key K) (V, bool) { return GetOk(m, key) }
   457  }
   458  
   459  // Contains checks is the map contains a key
   460  func Contains[M ~map[K]V, K comparable, V any](m M, key K) (ok bool) {
   461  	if m != nil {
   462  		_, ok = m[key]
   463  	}
   464  	return ok
   465  }
   466  
   467  // KeyChecker creates a function that can be used to check if the map contains a key
   468  func KeyChecker[M ~map[K]V, K comparable, V any](m M) func(key K) (ok bool) {
   469  	return func(key K) (ok bool) {
   470  		return Contains(m, key)
   471  	}
   472  }