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  }