github.com/m4gshm/gollections@v0.0.13-0.20240331203319-a34a86e58a24/kv/loop/api.go (about) 1 // Package loop provides helpers for loop operation over key/value pairs and iterator implementations 2 package loop 3 4 import ( 5 "github.com/m4gshm/gollections/break/kv/loop" 6 "github.com/m4gshm/gollections/c" 7 "github.com/m4gshm/gollections/map_/resolv" 8 ) 9 10 // New makes a loop from an abstract source 11 func New[S, K, V any](source S, hasNext func(S) bool, getNext func(S) (K, V)) Loop[K, V] { 12 return func() (k K, v V, ok bool) { 13 if hasNext(source) { 14 k, v = getNext(source) 15 return k, v, true 16 } 17 return k, v, false 18 } 19 } 20 21 // All is an adapter for the next function for iterating by `for ... range`. Supported since go 1.22 with GOEXPERIMENT=rangefunc enabled. 22 func All[K, V any](next func() (K, V, bool), consumer func(K, V) bool) { 23 for k, v, ok := next(); ok && consumer(k, v); k, v, ok = next() { 24 } 25 } 26 27 // Track applies the 'consumer' function to position/element pairs retrieved by the 'next' function until the consumer returns the c.Break to stop. 28 func Track[I, T any](next func() (I, T, bool), consumer func(I, T) error) error { 29 if next == nil { 30 return nil 31 } 32 for p, v, ok := next(); ok; p, v, ok = next() { 33 if err := consumer(p, v); err == c.Break { 34 return nil 35 } else if err != nil { 36 return err 37 } 38 } 39 return nil 40 } 41 42 // TrackEach applies the 'consumer' function to position/element pairs retrieved by the 'next' function 43 func TrackEach[I, T any](next func() (I, T, bool), consumer func(I, T)) { 44 if next == nil { 45 return 46 } 47 for p, v, ok := next(); ok; p, v, ok = next() { 48 consumer(p, v) 49 } 50 } 51 52 // Group collects sets of values grouped by keys obtained by passing a key/value iterator 53 func Group[K comparable, V any](next func() (K, V, bool)) map[K][]V { 54 return ToMapResolv(next, resolv.Slice[K, V]) 55 } 56 57 // Reduce reduces the key/value pairs retrieved by the 'next' function into an one pair using the 'merge' function 58 func Reduce[K, V any](next func() (K, V, bool), merge func(K, K, V, V) (K, V)) (rk K, rv V) { 59 if k, v, ok := next(); ok { 60 rk, rv = k, v 61 } else { 62 return rk, rv 63 } 64 for k, v, ok := next(); ok; k, v, ok = next() { 65 rk, rv = merge(rk, k, rv, v) 66 } 67 return rk, rv 68 } 69 70 // Reducee reduces the key/value pairs retrieved by the 'next' function into an one pair using the 'merge' function 71 func Reducee[K, V any](next func() (K, V, bool), merge func(K, K, V, V) (K, V, error)) (rk K, rv V, err error) { 72 k, v, ok := next() 73 if !ok { 74 return rk, rv, nil 75 } 76 rk, rv = k, v 77 for { 78 if k, v, ok := next(); !ok { 79 return rk, rv, nil 80 } else if rk, rv, err = merge(rk, k, rv, v); err != nil { 81 return rk, rv, err 82 } 83 } 84 } 85 86 // HasAny finds the first key/value pair that satisfies the 'predicate' function condition and returns true if successful 87 func HasAny[K, V any](next func() (K, V, bool), predicate func(K, V) bool) bool { 88 _, _, ok := First(next, predicate) 89 return ok 90 } 91 92 // HasAnyy finds the first key/value pair that satisfies the 'predicate' function condition and returns true if successful 93 func HasAnyy[K, V any](next func() (K, V, bool), predicate func(K, V) (bool, error)) (bool, error) { 94 _, _, ok, err := Firstt(next, predicate) 95 return ok, err 96 } 97 98 // First returns the first key/value pair that satisfies the condition of the 'predicate' function 99 func First[K, V any](next func() (K, V, bool), predicate func(K, V) bool) (K, V, bool) { 100 for { 101 if k, v, ok := next(); !ok { 102 return k, v, false 103 } else if ok := predicate(k, v); ok { 104 return k, v, true 105 } 106 } 107 } 108 109 // Firstt returns the first key/value pair that satisfies the condition of the 'predicate' function 110 func Firstt[K, V any](next func() (K, V, bool), predicate func(K, V) (bool, error)) (K, V, bool, error) { 111 for { 112 if k, v, ok := next(); !ok { 113 return k, v, false, nil 114 } else if ok, err := predicate(k, v); err != nil || ok { 115 return k, v, ok, err 116 } 117 } 118 } 119 120 // Convert creates a loop that applies the 'converter' function to iterable key\values. 121 func Convert[K, V any, KOUT, VOUT any](next func() (K, V, bool), converter func(K, V) (KOUT, VOUT)) Loop[KOUT, VOUT] { 122 if next == nil { 123 return nil 124 } 125 return func() (k2 KOUT, v2 VOUT, ok bool) { 126 if k, v, ok := next(); ok { 127 k2, v2 = converter(k, v) 128 return k2, v2, true 129 } 130 return k2, v2, false 131 } 132 } 133 134 // Conv creates a loop that applies the 'converter' function to iterable key\values. 135 func Conv[K, V any, KOUT, VOUT any](next func() (K, V, bool), converter func(K, V) (KOUT, VOUT, error)) loop.Loop[KOUT, VOUT] { 136 return loop.Conv(loop.From(next), converter) 137 } 138 139 // Filter creates a loop that checks elements by the 'filter' function and returns successful ones. 140 func Filter[K, V any](next func() (K, V, bool), filter func(K, V) bool) Loop[K, V] { 141 if next == nil { 142 return nil 143 } 144 return func() (K, V, bool) { 145 return First(next, filter) 146 } 147 } 148 149 // Filt creates a loop that checks elements by the 'filter' function and returns successful ones. 150 func Filt[K, V any](next func() (K, V, bool), filter func(K, V) (bool, error)) loop.Loop[K, V] { 151 return loop.Filt(loop.From(next), filter) 152 } 153 154 // ToMapResolv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values 155 func ToMapResolv[K comparable, V, VR any](next func() (K, V, bool), resolver func(bool, K, VR, V) VR) map[K]VR { 156 m := map[K]VR{} 157 for k, v, ok := next(); ok; k, v, ok = next() { 158 exists, ok := m[k] 159 m[k] = resolver(ok, k, exists, v) 160 } 161 return m 162 } 163 164 // ToMap collects key\value elements to a map by iterating over the elements 165 func ToMap[K comparable, V any](next func() (K, V, bool)) map[K]V { 166 return ToMapResolv(next, resolv.First[K, V]) 167 } 168 169 // ToSlice collects key\value elements to a slice by iterating over the elements 170 func ToSlice[K, V, T any](next func() (K, V, bool), converter func(K, V) T) []T { 171 s := []T{} 172 for key, val, ok := next(); ok; key, val, ok = next() { 173 s = append(s, converter(key, val)) 174 } 175 return s 176 } 177 178 // Crank rertieves next key\value from the 'next' function, returns the function, element, successfully flag. 179 func Crank[K, V any](next func() (K, V, bool)) (n Loop[K, V], k K, v V, ok bool) { 180 if next != nil { 181 k, v, ok = next() 182 } 183 return next, k, v, ok 184 }