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