github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/easy/maps.go (about)

     1  package easy
     2  
     3  // DiffMaps returns a new map which contains elements which present in m,
     4  // but not present in others.
     5  //
     6  // If length of m is zero, it returns nil.
     7  func DiffMaps[M ~map[K]V, K comparable, V any](m M, others ...M) M {
     8  	out := make(M)
     9  	for k, v := range m {
    10  		found := false
    11  		for _, b := range others {
    12  			if _, ok := b[k]; ok {
    13  				found = true
    14  				break
    15  			}
    16  		}
    17  		if !found {
    18  			out[k] = v
    19  		}
    20  	}
    21  	return out
    22  }
    23  
    24  // DiffMapsInplace removes elements that present in others from m.
    25  func DiffMapsInplace[M ~map[K]V, K comparable, V any](m M, others ...M) M {
    26  	for k := range m {
    27  		for _, m1 := range others {
    28  			if _, ok := m1[k]; ok {
    29  				delete(m, k)
    30  				break
    31  			}
    32  		}
    33  	}
    34  	return m
    35  }
    36  
    37  // FilterMaps iterates the given maps, it calls predicate(k, v) for each
    38  // key value in the maps and returns a new map of key value pairs for
    39  // which predicate(k, v) returns true.
    40  func FilterMaps[M ~map[K]V, K comparable, V any](predicate func(k K, v V) bool, maps ...M) M {
    41  	if len(maps) == 0 {
    42  		return nil
    43  	}
    44  	out := make(M, len(maps[0]))
    45  	for _, x := range maps {
    46  		for k, v := range x {
    47  			if predicate(k, v) {
    48  				out[k] = v
    49  			}
    50  		}
    51  	}
    52  	return out
    53  }
    54  
    55  // MergeMaps returns a new map containing all key values present in given maps.
    56  func MergeMaps[M ~map[K]V, K comparable, V any](maps ...M) M {
    57  	var length int
    58  	for _, m := range maps {
    59  		length += len(m)
    60  	}
    61  	dst := make(M, length)
    62  	for _, m := range maps {
    63  		for k, v := range m {
    64  			dst[k] = v
    65  		}
    66  	}
    67  	return dst
    68  }
    69  
    70  // MergeMapsTo adds key values present in others to the dst map.
    71  // If dst is a nil map, it creates a new map and returns it.
    72  func MergeMapsTo[M ~map[K]V, K comparable, V any](dst M, others ...M) M {
    73  	if len(others) == 0 {
    74  		return dst
    75  	}
    76  	if dst == nil {
    77  		dst = make(M, len(others[0]))
    78  	}
    79  	for _, m := range others {
    80  		for k, v := range m {
    81  			dst[k] = v
    82  		}
    83  	}
    84  	return dst
    85  }
    86  
    87  // MergeMapsToPtr is similar to MergeMapsTo, but it accepts a pointer as dst,
    88  // if dst points to a nil map, it creates a new map and assigns it to dst.
    89  // If dst is a nil pointer, it panics.
    90  func MergeMapsToPtr[M ~map[K]V, K comparable, V any](dst *M, others ...M) {
    91  	if dst == nil {
    92  		panic("easy.MergeMapsToPtr: dst must not be nil")
    93  	}
    94  	*dst = MergeMapsTo(*dst, others...)
    95  }
    96  
    97  // Keys returns the keys of the map m.
    98  // The keys will be in an indeterminate order.
    99  //
   100  // Optionally, a filter function can be given to make it returning
   101  // only keys for which filter(k, v) returns true.
   102  func Keys[M ~map[K]V, K comparable, V any](m M, filter ...func(K, V) bool) []K {
   103  	var f func(K, V) bool
   104  	if len(filter) > 0 {
   105  		f = filter[0]
   106  	}
   107  	keys := make([]K, 0, len(m))
   108  	if f == nil {
   109  		for k := range m {
   110  			keys = append(keys, k)
   111  		}
   112  	} else {
   113  		for k, v := range m {
   114  			if f(k, v) {
   115  				keys = append(keys, k)
   116  			}
   117  		}
   118  	}
   119  	return keys
   120  }
   121  
   122  // Values returns the values of the map m.
   123  // The values will be in an indeterminate order.
   124  //
   125  // Optionally, a filter function can be given to make it returning
   126  // only values for which filter(k, v) returns true.
   127  func Values[M ~map[K]V, K comparable, V any](m M, filter ...func(K, V) bool) []V {
   128  	var f func(K, V) bool
   129  	if len(filter) > 0 {
   130  		f = filter[0]
   131  	}
   132  	values := make([]V, 0, len(m))
   133  	if f == nil {
   134  		for _, v := range m {
   135  			values = append(values, v)
   136  		}
   137  	} else {
   138  		for k, v := range m {
   139  			if f(k, v) {
   140  				values = append(values, v)
   141  			}
   142  		}
   143  	}
   144  	return values
   145  }
   146  
   147  // CopyMap copies a map to be a new one.
   148  // optionalSize optionally specifies the size of the new map.
   149  func CopyMap[M ~map[K]V, K comparable, V any](m M, optionalSize ...int) M {
   150  	copySize := len(m)
   151  	if len(optionalSize) > 0 && optionalSize[0] > copySize {
   152  		copySize = optionalSize[0]
   153  	}
   154  	out := make(M, copySize)
   155  	for k, v := range m {
   156  		out[k] = v
   157  	}
   158  	return out
   159  }
   160  
   161  // SplitMap splits a large map to batches, it returns a slice
   162  // of type []M whose elements are subset of the given map.
   163  func SplitMap[M ~map[K]V, K comparable, V any](m M, batchSize int) []M {
   164  	if len(m) == 0 {
   165  		return nil
   166  	}
   167  	if len(m) <= batchSize {
   168  		return []M{m}
   169  	}
   170  
   171  	cnt := (len(m) + batchSize - 1) / batchSize
   172  	out := make([]M, cnt)
   173  	for i := range out {
   174  		if i < len(out)-1 {
   175  			out[i] = make(M, batchSize)
   176  		} else {
   177  			out[i] = make(M, len(m)%batchSize)
   178  		}
   179  	}
   180  	i := 0
   181  	for k, v := range m {
   182  		out[i/batchSize][k] = v
   183  		i++
   184  	}
   185  	return out
   186  }