github.com/m4gshm/gollections@v0.0.10/break/loop/api.go (about)

     1  // Package loop provides helpers for loop operation and iterator implementations
     2  package loop
     3  
     4  import (
     5  	"errors"
     6  
     7  	"github.com/m4gshm/gollections/break/predicate/always"
     8  	"github.com/m4gshm/gollections/c"
     9  	"github.com/m4gshm/gollections/convert"
    10  	"github.com/m4gshm/gollections/convert/as"
    11  	"github.com/m4gshm/gollections/map_/resolv"
    12  	"github.com/m4gshm/gollections/notsafe"
    13  	"github.com/m4gshm/gollections/op"
    14  	"github.com/m4gshm/gollections/op/check/not"
    15  )
    16  
    17  // ErrBreak is the 'break' statement of the For, Track methods
    18  var ErrBreak = c.ErrBreak
    19  
    20  // Looper provides an iterable loop function
    21  type Looper[T any, I interface{ Next() (T, bool, error) }] interface {
    22  	Loop() I
    23  }
    24  
    25  // Of wrap the elements by loop function
    26  func Of[T any](elements ...T) func() (e T, ok bool, err error) {
    27  	l := len(elements)
    28  	i := 0
    29  	if l == 0 || i < 0 || i >= l {
    30  		return func() (e T, ok bool, err error) { return e, false, nil }
    31  	}
    32  	return func() (e T, ok bool, err error) {
    33  		if i < l {
    34  			e, ok = elements[i], true
    35  			i++
    36  		}
    37  		return e, ok, nil
    38  	}
    39  }
    40  
    41  // From wrap the next loop to a breakable loop
    42  func From[T any](next func() (T, bool)) func() (T, bool, error) {
    43  	return func() (T, bool, error) {
    44  		e, ok := next()
    45  		return e, ok, nil
    46  	}
    47  }
    48  
    49  // To transforms a breakable loop to a simple loop.
    50  // The errConsumer is a function that is called when an error occurs.
    51  func To[T any](next func() (T, bool, error), errConsumer func(error)) func() (T, bool) {
    52  	return func() (T, bool) {
    53  		e, ok, err := next()
    54  		if err != nil {
    55  			errConsumer(err)
    56  			return e, false
    57  		}
    58  		return e, ok
    59  	}
    60  }
    61  
    62  // For applies the 'walker' function for the elements retrieved by the 'next' function. Return the c.ErrBreak to stop
    63  func For[T any](next func() (T, bool, error), walker func(T) error) error {
    64  	for {
    65  		if v, ok, err := next(); err != nil || !ok {
    66  			return err
    67  		} else if err := walker(v); err != nil {
    68  			return brk(err)
    69  		}
    70  	}
    71  }
    72  
    73  // ForFiltered applies the 'walker' function to the elements retrieved by the 'next' function that satisfy the 'predicate' function condition
    74  func ForFiltered[T any](next func() (T, bool, error), walker func(T) error, predicate func(T) bool) error {
    75  	for {
    76  		if v, ok, err := next(); err != nil || !ok {
    77  			return err
    78  		} else if ok := predicate(v); ok {
    79  			if err := walker(v); err != nil {
    80  				return brk(err)
    81  			}
    82  		}
    83  	}
    84  }
    85  
    86  // First returns the first element that satisfies the condition of the 'predicate' function
    87  func First[T any](next func() (T, bool, error), predicate func(T) bool) (T, bool, error) {
    88  	for {
    89  		if out, ok, err := next(); err != nil || !ok {
    90  			return out, false, err
    91  		} else if ok := predicate(out); ok {
    92  			return out, true, nil
    93  		}
    94  	}
    95  }
    96  
    97  // Firstt returns the first element that satisfies the condition of the 'predicate' function
    98  func Firstt[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (T, bool, error) {
    99  	for {
   100  		if out, ok, err := next(); err != nil || !ok {
   101  			return out, false, err
   102  		} else if ok, err := predicate(out); err != nil || ok {
   103  			return out, ok, err
   104  		}
   105  	}
   106  }
   107  
   108  // Track applies the 'tracker' function to position/element pairs retrieved by the 'next' function. Return the c.ErrBreak to stop tracking..
   109  func Track[I, T any](next func() (I, T, bool, error), tracker func(I, T) error) error {
   110  	for {
   111  		if p, v, ok, err := next(); err != nil || !ok {
   112  			return err
   113  		} else if err := tracker(p, v); err != nil {
   114  			return brk(err)
   115  		}
   116  	}
   117  }
   118  
   119  // Slice collects the elements retrieved by the 'next' function into a slice
   120  func Slice[T any](next func() (T, bool, error)) (out []T, err error) {
   121  	for {
   122  		v, ok, err := next()
   123  		if ok {
   124  			out = append(out, v)
   125  		}
   126  		if !ok || err != nil {
   127  			return out, err
   128  		}
   129  	}
   130  }
   131  
   132  // SliceCap collects the elements retrieved by the 'next' function into a new slice with predefined capacity
   133  func SliceCap[T any](next func() (T, bool, error), cap int) (out []T, err error) {
   134  	if cap > 0 {
   135  		out = make([]T, 0, cap)
   136  	}
   137  	return Append(next, out)
   138  }
   139  
   140  // Append collects the elements retrieved by the 'next' function into the specified 'out' slice
   141  func Append[T any, TS ~[]T](next func() (T, bool, error), out TS) (TS, error) {
   142  	for v, ok, err := next(); ok; v, ok, err = next() {
   143  		if err != nil {
   144  			return out, err
   145  		}
   146  		out = append(out, v)
   147  	}
   148  	return out, nil
   149  }
   150  
   151  // Reduce reduces the elements retrieved by the 'next' function into an one using the 'merge' function
   152  func Reduce[T any](next func() (T, bool, error), merger func(T, T) T) (out T, e error) {
   153  	v, ok, err := next()
   154  	if err != nil || !ok {
   155  		return out, err
   156  	}
   157  	out = v
   158  	for {
   159  		v, ok, err := next()
   160  		if err != nil || !ok {
   161  			return out, err
   162  		}
   163  		out = merger(out, v)
   164  	}
   165  }
   166  
   167  // Reducee reduces the elements retrieved by the 'next' function into an one using the 'merge' function
   168  func Reducee[T any](next func() (T, bool, error), merger func(T, T) (T, error)) (out T, e error) {
   169  	v, ok, err := next()
   170  	if err != nil || !ok {
   171  		return out, err
   172  	}
   173  	out = v
   174  	for {
   175  		if v, ok, err := next(); err != nil || !ok {
   176  			return out, err
   177  		} else if out, err = merger(out, v); err != nil {
   178  			return out, err
   179  		}
   180  	}
   181  }
   182  
   183  // Sum returns the sum of all elements
   184  func Sum[T c.Summable](next func() (T, bool, error)) (T, error) {
   185  	return Reduce(next, op.Sum[T])
   186  }
   187  
   188  // HasAny finds the first element that satisfies the 'predicate' function condition and returns true if successful
   189  func HasAny[T any](next func() (T, bool, error), predicate func(T) bool) (bool, error) {
   190  	_, ok, err := First(next, predicate)
   191  	return ok, err
   192  }
   193  
   194  // HasAnyy finds the first element that satisfies the 'predicate' function condition and returns true if successful
   195  func HasAnyy[T any](next func() (T, bool, error), predicate func(T) (bool, error)) (bool, error) {
   196  	_, ok, err := Firstt(next, predicate)
   197  	return ok, err
   198  }
   199  
   200  // Contains  finds the first element that equal to the example and returns true
   201  func Contains[T comparable](next func() (T, bool, error), example T) (bool, error) {
   202  	for {
   203  		if one, ok, err := next(); err != nil || !ok {
   204  			return false, err
   205  		} else if one == example {
   206  			return true, nil
   207  		}
   208  	}
   209  }
   210  
   211  // Conv instantiates an iterator that converts elements with a converter and returns them.
   212  func Conv[From, To any](next func() (From, bool, error), converter func(From) (To, error)) ConvertIter[From, To] {
   213  	return ConvertIter[From, To]{next: next, converter: converter}
   214  }
   215  
   216  // Convert instantiates an iterator that converts elements with a converter and returns them.
   217  func Convert[From, To any](next func() (From, bool, error), converter func(From) To) ConvertIter[From, To] {
   218  	return ConvertIter[From, To]{next: next, converter: func(f From) (To, error) { return converter(f), nil }}
   219  }
   220  
   221  // ConvCheck is similar to ConvertFilt, but it checks and transforms elements together
   222  func ConvCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool, error)) ConvertCheckIter[From, To] {
   223  	return ConvertCheckIter[From, To]{next: next, converter: converter}
   224  }
   225  
   226  // ConvertCheck is similar to ConvFilt, but it checks and transforms elements together
   227  func ConvertCheck[From, To any](next func() (From, bool, error), converter func(from From) (To, bool)) ConvertCheckIter[From, To] {
   228  	return ConvertCheckIter[From, To]{next: next, converter: func(f From) (To, bool, error) { c, ok := converter(f); return c, ok, nil }}
   229  }
   230  
   231  // FiltAndConv returns a stream that filters source elements and converts them
   232  func FiltAndConv[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error)) ConvFiltIter[From, To] {
   233  	return FilterConvertFilter(next, filter, converter, always.True[To])
   234  }
   235  
   236  // FilterAndConvert returns a stream that filters source elements and converts them
   237  func FilterAndConvert[From, To any](next func() (From, bool, error), filter func(From) bool, converter func(From) To) ConvFiltIter[From, To] {
   238  	return FilterConvertFilter(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) (To, error) { return converter(f), nil }, always.True[To])
   239  }
   240  
   241  // FilterConvertFilter filters source, converts, and filters converted elements
   242  func FilterConvertFilter[From, To any](next func() (From, bool, error), filter func(From) (bool, error), converter func(From) (To, error), filterTo func(To) (bool, error)) ConvFiltIter[From, To] {
   243  	return ConvFiltIter[From, To]{next: next, converter: converter, filterFrom: filter, filterTo: filterTo}
   244  }
   245  
   246  // ConvertAndFilter additionally filters 'To' elements
   247  func ConvertAndFilter[From, To any](next func() (From, bool, error), converter func(From) (To, error), filter func(To) (bool, error)) ConvFiltIter[From, To] {
   248  	return FilterConvertFilter(next, always.True[From], converter, filter)
   249  }
   250  
   251  // Flatt instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements.
   252  func Flatt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error)) *FlatIter[From, To] {
   253  	return &FlatIter[From, To]{next: next, flattener: flattener, elemSizeTo: notsafe.GetTypeSize[To]()}
   254  }
   255  
   256  // Flat instantiates an iterator that extracts slices of 'To' by a flattener from elements of 'From' and flattens as one iterable collection of 'To' elements.
   257  func Flat[From, To any](next func() (From, bool, error), flattener func(From) []To) *FlatIter[From, To] {
   258  	return &FlatIter[From, To]{next: next, flattener: func(f From) ([]To, error) { return flattener(f), nil }, elemSizeTo: notsafe.GetTypeSize[To]()}
   259  }
   260  
   261  // FiltAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function
   262  func FiltAndFlat[From, To any](next func() (From, bool, error), filter func(From) (bool, error), flattener func(From) ([]To, error)) *FlattFiltIter[From, To] {
   263  	return FiltFlattFilt(next, filter, flattener, always.True[To])
   264  }
   265  
   266  // FilterAndFlat filters source elements and extracts slices of 'To' by the 'flattener' function
   267  func FilterAndFlat[From, To any](next func() (From, bool, error), filter func(From) bool, flattener func(From) []To) *FlattFiltIter[From, To] {
   268  	return FiltFlattFilt(next, func(f From) (bool, error) { return filter(f), nil }, func(f From) ([]To, error) { return flattener(f), nil }, always.True[To])
   269  }
   270  
   271  // FlatAndFilt extracts slices of 'To' by the 'flattener' function and filters extracted elements
   272  func FlatAndFilt[From, To any](next func() (From, bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *FlattFiltIter[From, To] {
   273  	return FiltFlattFilt(next, always.True[From], flattener, filterTo)
   274  }
   275  
   276  // FlattAndFilter extracts slices of 'To' by the 'flattener' function and filters extracted elements
   277  func FlattAndFilter[From, To any](next func() (From, bool, error), flattener func(From) []To, filterTo func(To) bool) *FlattFiltIter[From, To] {
   278  	return FiltFlattFilt(next, always.True[From], func(f From) ([]To, error) { return flattener(f), nil }, func(t To) (bool, error) { return filterTo(t), nil })
   279  }
   280  
   281  // FiltFlattFilt filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements
   282  func FiltFlattFilt[From, To any](next func() (From, bool, error), filterFrom func(From) (bool, error), flattener func(From) ([]To, error), filterTo func(To) (bool, error)) *FlattFiltIter[From, To] {
   283  	return &FlattFiltIter[From, To]{next: next, filterFrom: filterFrom, flattener: flattener, filterTo: filterTo, elemSizeTo: notsafe.GetTypeSize[To]()}
   284  }
   285  
   286  // FilterFlatFilter filters source elements, extracts slices of 'To' by the 'flattener' function and filters extracted elements
   287  func FilterFlatFilter[From, To any](next func() (From, bool, error), filterFrom func(From) bool, flattener func(From) []To, filterTo func(To) bool) *FlattFiltIter[From, To] {
   288  	return &FlattFiltIter[From, To]{
   289  		next:       next,
   290  		filterFrom: func(f From) (bool, error) { return filterFrom(f), nil },
   291  		flattener:  func(f From) ([]To, error) { return flattener(f), nil },
   292  		filterTo:   func(t To) (bool, error) { return filterTo(t), nil },
   293  		elemSizeTo: notsafe.GetTypeSize[To](),
   294  	}
   295  }
   296  
   297  // Filt creates an iterator that checks elements by the 'filter' function and returns successful ones.
   298  func Filt[T any](next func() (T, bool, error), filter func(T) (bool, error)) FiltIter[T] {
   299  	return FiltIter[T]{next: next, filter: filter}
   300  }
   301  
   302  // Filter creates an iterator that checks elements by the 'filter' function and returns successful ones.
   303  func Filter[T any](next func() (T, bool, error), filter func(T) bool) FiltIter[T] {
   304  	return FiltIter[T]{next: next, filter: as.ErrTail(filter)}
   305  }
   306  
   307  // NotNil creates an iterator that filters nullable elements.
   308  func NotNil[T any](next func() (*T, bool, error)) FiltIter[*T] {
   309  	return Filt(next, as.ErrTail(not.Nil[T]))
   310  }
   311  
   312  // PtrVal creates an iterator that transform pointers to the values referenced by those pointers.
   313  // Nil pointers are transformet to zero values.
   314  func PtrVal[T any](next func() (*T, bool, error)) ConvertIter[*T, T] {
   315  	return Convert(next, convert.PtrVal[T])
   316  }
   317  
   318  // NoNilPtrVal creates an iterator that transform only not nil pointers to the values referenced referenced by those pointers.
   319  // Nil pointers are ignored.
   320  func NoNilPtrVal[T any](next func() (*T, bool, error)) ConvertCheckIter[*T, T] {
   321  	return ConvertCheck(next, convert.NoNilPtrVal[T])
   322  }
   323  
   324  // KeyValue transforms iterable elements to key/value iterator based on applying key, value extractors to the elements
   325  func KeyValue[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) KeyValuer[T, K, V] {
   326  	return KeyValuee(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor))
   327  }
   328  
   329  // KeyValuee transforms iterable elements to key/value iterator based on applying key, value extractors to the elements
   330  func KeyValuee[T any, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) KeyValuer[T, K, V] {
   331  	return NewKeyValuer(next, keyExtractor, valExtractor)
   332  }
   333  
   334  // KeysValues transforms iterable elements to key/value iterator based on applying multiple keys, values extractor to the elements
   335  func KeysValues[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, K, V] {
   336  	return NewMultipleKeyValuer(next, keysExtractor, valsExtractor)
   337  }
   338  
   339  // KeysValue transforms iterable elements to key/value iterator based on applying key, value extractor to the elements
   340  func KeysValue[T, K, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) *MultipleKeyValuer[T, K, V] {
   341  	return KeysValues(next, as.ErrTail(keysExtractor), convSlice(as.ErrTail(valExtractor)))
   342  }
   343  
   344  // KeysValuee transforms iterable elements to key/value iterator based on applying key, value extractor to the elements
   345  func KeysValuee[T, K, V any](next func() (T, bool, error), keysExtractor func(T) ([]K, error), valExtractor func(T) (V, error)) *MultipleKeyValuer[T, K, V] {
   346  	return KeysValues(next, keysExtractor, convSlice(valExtractor))
   347  }
   348  
   349  // KeyValues transforms iterable elements to key/value iterator based on applying key, value extractor to the elements
   350  func KeyValues[T, K, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) *MultipleKeyValuer[T, K, V] {
   351  	return KeysValues(next, convSlice(as.ErrTail(keyExtractor)), as.ErrTail(valsExtractor))
   352  }
   353  
   354  // KeyValuess transforms iterable elements to key/value iterator based on applying key, value extractor to the elements
   355  func KeyValuess[T, K, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, K, V] {
   356  	return KeysValues(next, convSlice(keyExtractor), valsExtractor)
   357  }
   358  
   359  // ExtraVals transforms iterable elements to key/value iterator based on applying value extractor to the elements
   360  func ExtraVals[T, V any](next func() (T, bool, error), valsExtractor func(T) []V) *MultipleKeyValuer[T, T, V] {
   361  	return KeyValues(next, as.Is[T], valsExtractor)
   362  }
   363  
   364  // ExtraValss transforms iterable elements to key/value iterator based on applying values extractor to the elements
   365  func ExtraValss[T, V any](next func() (T, bool, error), valsExtractor func(T) ([]V, error)) *MultipleKeyValuer[T, T, V] {
   366  	return KeyValuess(next, as.ErrTail(as.Is[T]), valsExtractor)
   367  }
   368  
   369  // ExtraKeys transforms iterable elements to key/value iterator based on applying key extractor to the elements
   370  func ExtraKeys[T, K any](next func() (T, bool, error), keysExtractor func(T) []K) *MultipleKeyValuer[T, K, T] {
   371  	return KeysValue(next, keysExtractor, as.Is[T])
   372  }
   373  
   374  // ExtraKeyss transforms iterable elements to key/value iterator based on applying key extractor to the elements
   375  func ExtraKeyss[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) *MultipleKeyValuer[T, K, T] {
   376  	return KeyValuess(next, keyExtractor, as.ErrTail(convert.AsSlice[T]))
   377  }
   378  
   379  // ExtraKey transforms iterable elements to key/value iterator based on applying key extractor to the elements
   380  func ExtraKey[T, K any](next func() (T, bool, error), keysExtractor func(T) K) KeyValuer[T, K, T] {
   381  	return KeyValue(next, keysExtractor, as.Is[T])
   382  }
   383  
   384  // ExtraKeyy transforms iterable elements to key/value iterator based on applying key extractor to the elements
   385  func ExtraKeyy[T, K any](next func() (T, bool, error), keyExtractor func(T) (K, error)) KeyValuer[T, K, T] {
   386  	return KeyValuee[T, K](next, keyExtractor, as.ErrTail(as.Is[T]))
   387  }
   388  
   389  // ExtraValue transforms iterable elements to key/value iterator based on applying value extractor to the elements
   390  func ExtraValue[T, V any](next func() (T, bool, error), valueExtractor func(T) V) KeyValuer[T, T, V] {
   391  	return KeyValue(next, as.Is[T], valueExtractor)
   392  }
   393  
   394  // ExtraValuee transforms iterable elements to key/value iterator based on applying value extractor to the elements
   395  func ExtraValuee[T, V any](next func() (T, bool, error), valExtractor func(T) (V, error)) KeyValuer[T, T, V] {
   396  	return KeyValuee[T, T, V](next, as.ErrTail(as.Is[T]), valExtractor)
   397  }
   398  
   399  // Group converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'.
   400  // The keyExtractor converts an element to a key.
   401  // The valExtractor converts an element to an value.
   402  func Group[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valExtractor func(T) V) (map[K][]V, error) {
   403  	return Groupp(next, as.ErrTail(keyExtractor), as.ErrTail(valExtractor))
   404  }
   405  
   406  // Groupp converts elements retrieved by the 'next' function into a map, extracting a key for each element applying the converter 'keyExtractor'.
   407  // The keyExtractor converts an element to a key.
   408  // The valExtractor converts an element to an value.
   409  func Groupp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K][]V, error) {
   410  	return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv []V, v V) ([]V, error) {
   411  		return resolv.Append(ok, k, rv, v), nil
   412  	})
   413  }
   414  
   415  // GroupByMultiple converts elements retrieved by the 'next' function into a map, extracting multiple keys, values per each element applying the 'keysExtractor' and 'valsExtractor' functions.
   416  // The keysExtractor retrieves one or more keys per element.
   417  // The valsExtractor retrieves one or more values per element.
   418  func GroupByMultiple[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valsExtractor func(T) []V) (map[K][]V, error) {
   419  	groups := map[K][]V{}
   420  	for {
   421  		if e, ok, err := next(); err != nil || !ok {
   422  			return groups, err
   423  		} else if keys, vals := keysExtractor(e), valsExtractor(e); len(keys) == 0 {
   424  			var key K
   425  			for _, v := range vals {
   426  				initGroup(key, v, groups)
   427  			}
   428  		} else {
   429  			for _, key := range keys {
   430  				if len(vals) == 0 {
   431  					var v V
   432  					initGroup(key, v, groups)
   433  				} else {
   434  					for _, v := range vals {
   435  						initGroup(key, v, groups)
   436  					}
   437  				}
   438  			}
   439  		}
   440  	}
   441  }
   442  
   443  // GroupByMultipleKeys converts elements retrieved by the 'next' function into a map, extracting multiple keys, one value per each element applying the 'keysExtractor' and 'valExtractor' functions.
   444  // The keysExtractor retrieves one or more keys per element.
   445  // The valExtractor converts an element to a value.
   446  func GroupByMultipleKeys[T any, K comparable, V any](next func() (T, bool, error), keysExtractor func(T) []K, valExtractor func(T) V) (map[K][]V, error) {
   447  	groups := map[K][]V{}
   448  	for {
   449  		if e, ok, err := next(); err != nil || !ok {
   450  			return groups, err
   451  		} else if keys, v := keysExtractor(e), valExtractor(e); len(keys) == 0 {
   452  			var key K
   453  			initGroup(key, v, groups)
   454  		} else {
   455  			for _, key := range keys {
   456  				initGroup(key, v, groups)
   457  			}
   458  		}
   459  	}
   460  }
   461  
   462  // GroupByMultipleValues converts elements retrieved by the 'next' function into a map, extracting one key, multiple values per each element applying the 'keyExtractor' and 'valsExtractor' functions.
   463  // The keyExtractor converts an element to a key.
   464  // The valsExtractor retrieves one or more values per element.
   465  func GroupByMultipleValues[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) K, valsExtractor func(T) []V) (map[K][]V, error) {
   466  	groups := map[K][]V{}
   467  	for {
   468  		if e, ok, err := next(); err != nil || !ok {
   469  			return groups, err
   470  		} else if key, vals := keyExtractor(e), valsExtractor(e); len(vals) == 0 {
   471  			var v V
   472  			initGroup(key, v, groups)
   473  		} else {
   474  			for _, v := range vals {
   475  				initGroup(key, v, groups)
   476  			}
   477  		}
   478  	}
   479  }
   480  
   481  func initGroup[T any, K comparable, TS ~[]T](key K, e T, groups map[K]TS) {
   482  	groups[key] = append(groups[key], e)
   483  }
   484  
   485  // ToMap collects key\value elements to a map by iterating over the elements
   486  func ToMap[T any, K comparable, V any](next func() (T, bool), keyExtractor func(T) K, valExtractor func(T) V) (map[K]V, error) {
   487  	return ToMapp(From(next), as.ErrTail(keyExtractor), as.ErrTail(valExtractor))
   488  }
   489  
   490  // ToMapp collects key\value elements to a map by iterating over the elements
   491  func ToMapp[T any, K comparable, V any](next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error)) (map[K]V, error) {
   492  	return ToMapResolvv(next, keyExtractor, valExtractor, func(ok bool, k K, rv V, v V) (V, error) { return resolv.First(ok, k, rv, v), nil })
   493  }
   494  
   495  // ToMapResolvv collects key\value elements to a map by iterating over the elements with resolving of duplicated key values
   496  func ToMapResolvv[T any, K comparable, V, VR any](
   497  	next func() (T, bool, error), keyExtractor func(T) (K, error), valExtractor func(T) (V, error),
   498  	resolver func(bool, K, VR, V) (VR, error),
   499  ) (m map[K]VR, err error) {
   500  	m = map[K]VR{}
   501  	for {
   502  		if e, ok, err := next(); err != nil || !ok {
   503  			return m, err
   504  		} else if k, err := keyExtractor(e); err != nil {
   505  			return m, err
   506  		} else if v, err := valExtractor(e); err != nil {
   507  			return m, err
   508  		} else {
   509  			exists, ok := m[k]
   510  			if m[k], err = resolver(ok, k, exists, v); err != nil {
   511  				return m, err
   512  			}
   513  		}
   514  	}
   515  }
   516  
   517  // New is the main breakable loop constructor
   518  func New[S, T any](source S, hasNext func(S) bool, getNext func(S) (T, error)) func() (T, bool, error) {
   519  	return func() (out T, ok bool, err error) {
   520  		if ok := hasNext(source); !ok {
   521  			return out, false, nil
   522  		} else if n, err := getNext(source); err != nil {
   523  			return out, false, err
   524  		} else {
   525  			return n, true, nil
   526  		}
   527  	}
   528  }
   529  
   530  // ConvertAndReduce converts each elements and merges them into one
   531  func ConvertAndReduce[From, To any](next func() (From, bool, error), converter func(From) To, merger func(To, To) To) (out To, err error) {
   532  	return Reduce(Convert(next, converter).Next, merger)
   533  }
   534  
   535  // ConvAndReduce converts each elements and merges them into one
   536  func ConvAndReduce[From, To any](next func() (From, bool, error), converter func(From) (To, error), merger func(To, To) To) (out To, err error) {
   537  	return Reduce(Conv(next, converter).Next, merger)
   538  }
   539  
   540  func brk(err error) error {
   541  	if errors.Is(err, c.ErrBreak) {
   542  		return nil
   543  	}
   544  	return err
   545  }
   546  
   547  func convSlice[T, V any](conv func(T) (V, error)) func(t T) ([]V, error) {
   548  	return func(t T) ([]V, error) {
   549  		v, err := conv(t)
   550  		if err != nil {
   551  			return nil, err
   552  		}
   553  		return convert.AsSlice(v), nil
   554  	}
   555  }