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  }