github.com/m4gshm/gollections@v0.0.10/break/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/map_/resolv" 6 ) 7 8 // Looper provides an iterable loop function 9 type Looper[K, V any, I interface{ Next() (K, V, bool, error) }] interface { 10 Loop() I 11 } 12 13 // From wrap the next loop to a breakable loop 14 func From[K, V any](next func() (K, V, bool)) func() (K, V, bool, error) { 15 return func() (K, V, bool, error) { 16 k, v, ok := next() 17 return k, v, ok, nil 18 } 19 } 20 21 // To transforms a breakable loop to a simple loop. 22 // The errConsumer is a function that is called when an error occurs. 23 func To[K, V any](next func() (K, V, bool, error), errConsumer func(error)) func() (K, V, bool) { 24 return func() (K, V, bool) { 25 k, v, ok, err := next() 26 if err != nil { 27 errConsumer(err) 28 return k, v, false 29 } 30 return k, v, ok 31 } 32 } 33 34 // Group collects sets of values grouped by keys obtained by passing a key/value iterator 35 func Group[K comparable, V any](next func() (K, V, bool, error)) (map[K][]V, error) { 36 return ToMapResolv(next, resolv.Append[K, V]) 37 } 38 39 // Reduce reduces the key/value pairs retrieved by the 'next' function into an one pair using the 'merge' function 40 func Reduce[K, V any](next func() (K, V, bool, error), merge func(K, K, V, V) (K, V)) (rk K, rv V, err error) { 41 k, v, ok, err := next() 42 if err != nil || !ok { 43 return rk, rv, err 44 } 45 rk, rv = k, v 46 for { 47 k, v, ok, err := next() 48 if err != nil || !ok { 49 return rk, rv, err 50 } 51 rk, rv = merge(rk, k, rv, v) 52 } 53 } 54 55 // Reducee reduces the key/value pairs retrieved by the 'next' function into an one pair using the 'merge' function 56 func Reducee[K, V any](next func() (K, V, bool, error), merge func(K, K, V, V) (K, V, error)) (rk K, rv V, err error) { 57 k, v, ok, err := next() 58 if err != nil || !ok { 59 return rk, rv, err 60 } 61 rk, rv = k, v 62 for { 63 if k, v, ok, err := next(); err != nil || !ok { 64 return rk, rv, err 65 } else if rk, rv, err = merge(rk, k, rv, v); err != nil { 66 return rk, rv, err 67 } 68 } 69 } 70 71 // HasAny finds the first key/value pair that satisfies the 'predicate' function condition and returns true if successful 72 func HasAny[K, V any](next func() (K, V, bool, error), predicate func(K, V) bool) (bool, error) { 73 _, _, ok, err := First(next, predicate) 74 return ok, err 75 } 76 77 // HasAnyy finds the first key/value pair that satisfies the 'predicate' function condition and returns true if successful 78 func HasAnyy[K, V any](next func() (K, V, bool, error), predicate func(K, V) (bool, error)) (bool, error) { 79 _, _, ok, err := Firstt(next, predicate) 80 return ok, err 81 } 82 83 // First returns the first key/value pair that satisfies the condition of the 'predicate' function 84 func First[K, V any](next func() (K, V, bool, error), predicate func(K, V) bool) (K, V, bool, error) { 85 for { 86 if k, v, ok, err := next(); err != nil || !ok { 87 return k, v, false, err 88 } else if ok := predicate(k, v); ok { 89 return k, v, true, nil 90 } 91 } 92 } 93 94 // Firstt returns the first key/value pair that satisfies the condition of the 'predicate' function 95 func Firstt[K, V any](next func() (K, V, bool, error), predicate func(K, V) (bool, error)) (K, V, bool, error) { 96 for { 97 if k, v, ok, err := next(); err != nil || !ok { 98 return k, v, false, err 99 } else if ok, err := predicate(k, v); err != nil || ok { 100 return k, v, ok, err 101 } 102 } 103 } 104 105 // Convert creates an iterator that applies a transformer to iterable key\values. 106 func Convert[K, V any, KOUT, VOUT any](next func() (K, V, bool, error), converter func(K, V) (KOUT, VOUT)) ConvertIter[K, V, KOUT, VOUT] { 107 return ConvertIter[K, V, KOUT, VOUT]{next: next, converter: func(k K, v V) (KOUT, VOUT, error) { ko, vo := converter(k, v); return ko, vo, nil }} 108 } 109 110 // Conv creates an iterator that applies a transformer to iterable key\values. 111 func Conv[K, V any, KOUT, VOUT any](next func() (K, V, bool, error), converter func(K, V) (KOUT, VOUT, error)) ConvertIter[K, V, KOUT, VOUT] { 112 return ConvertIter[K, V, KOUT, VOUT]{next: next, converter: converter} 113 } 114 115 // Filter creates an iterator that checks elements by a filter and returns successful ones 116 func Filter[K, V any](next func() (K, V, bool, error), filter func(K, V) bool) FiltIter[K, V] { 117 return FiltIter[K, V]{next: next, filter: func(k K, v V) (bool, error) { return filter(k, v), nil }} 118 } 119 120 // Filt creates an iterator that checks elements by a filter and returns successful ones 121 func Filt[K, V any](next func() (K, V, bool, error), filter func(K, V) (bool, error)) FiltIter[K, V] { 122 return FiltIter[K, V]{next: next, filter: filter} 123 } 124 125 // ToMapResolv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values 126 func ToMapResolv[K comparable, V, VR any](next func() (K, V, bool, error), resolver func(bool, K, VR, V) VR) (map[K]VR, error) { 127 m := map[K]VR{} 128 for { 129 k, v, ok, err := next() 130 if err != nil || !ok { 131 return m, err 132 } 133 exists, ok := m[k] 134 m[k] = resolver(ok, k, exists, v) 135 } 136 } 137 138 // ToMap collects key\value elements to a map by iterating over the elements 139 func ToMap[K comparable, V any](next func() (K, V, bool, error)) (map[K]V, error) { 140 return ToMapResolv(next, resolv.First[K, V]) 141 } 142 143 // ToSlice collects key\value elements to a slice by iterating over the elements 144 func ToSlice[K, V, T any](next func() (K, V, bool, error), converter func(K, V) T) ([]T, error) { 145 s := []T{} 146 for { 147 key, val, ok, err := next() 148 if ok { 149 s = append(s, converter(key, val)) 150 } 151 if !ok || err != nil { 152 return s, err 153 } 154 } 155 } 156 157 // New is the mai breakable key/value loop constructor 158 func New[S, K, V any](source S, hasNext func(S) bool, getNext func(S) (K, V, error)) func() (K, V, bool, error) { 159 return func() (k K, v V, ok bool, err error) { 160 if ok := hasNext(source); !ok { 161 return k, v, false, nil 162 } else if k, v, err = getNext(source); err != nil { 163 return k, v, false, err 164 } else { 165 return k, v, true, nil 166 } 167 } 168 }