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 }