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 }