✨ yuemori/enu
is a Enumerator library based on Go 1.18+ Generics.
This package that provides functions for manipulationg collections like C# IEnumerable or Ruby Enumerable.
We prefer C# IEnumerable and Ruby Enumerable because there modules can be manipurated with a same interfaces and functions for various enumerable collections.
Note: This package inspire and used internally samber/lo functions. Thanks.
go get github.com/yuemori/enu
You can import enu
using:
import "github.com/yuemori/enu"
Then use one of the example below:
count := enu.From([]int{1, 2, 3, 4, 5}).Count()
// 5
r := enu.From([]int{1, 2, 3, 4, 5}).Filter(func(i int, _ int) bool {
return i%2 != 0
}).ToSlice()
// []int{1, 3, 5}
enu
provides Enumerators
and Enumerables
.
Enumerator
provides iteration over collection (slice, map, channel, generator...).
Enumerable
supports a iteration over a collection of a specific type (int, string, struct...).
example below:
// SliceEnumerator provides generic iteration for slice
enumerable := enu.NewSliceEnumerator([]int{1, 2, 3})
// Enumerable provides enumerator interfaces
enumerator := enu.New(enumerable)
r := enumerator.Count()
// 3
Enumerable
supports mathod chaining.
example below:
r := enu.From([]int{1, 2, 3, 4, 5}).Filter(func(i int, _ int) bool {
return i%2 != 0
}).Reverse().ToSlice()
// []int{5, 3, 1}
Importantly, Enuemrable
postpone enumeration and enumerate values only an as-needed basis.
So the Enumerable
only asks the Enumerator
for the number it needs.
See below examples:
Range
// `enu.FromNumericRange(1, math.MaxInt)` Returns range from 1 to infinity.
r := enu.FromNumericRange(1, math.MaxInt).Take(10).ToSlice()
// []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Generator
// fibonacci number generator
fibonacci := func() func(int) (int, bool) {
n, n1 := 0, 1
return func(i int) (int, bool) {
v := n
n, n1 = n1, n+n1
return v, true
}
}
r := enu.FromFunc(fibonacci()).Take(10).ToSlice()
// []int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}
Channel
ch1 := make(chan (int), 1)
go func() {
defer close(ch1)
for i := 1; i < 6; i++ {
ch1 <- i
}
}()
// iterate to be channel closed
r := enu.FromChannel(ch1).ToSlice()
// []int{1, 2, 3, 4, 5}
ch2 := make(chan (int), 1)
defer close(ch2)
go func() {
for i := 1; i < 6; i++ {
ch2 <- i
}
}()
// or limited iteration
r := enu.FromChannel(ch2).Take(3).ToSlice()
// []int{1, 2, 3}
and helper functions to use:
request1 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"https://google.com", nil}
}
request2 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"https://amazon.co.jp", nil}
}
request3 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"", errors.New("some error")}
}
// Aggregate multiple function result by async
r := enu.FromChannel(enu.Parallel(2, request1, request2, request3)).ToSlice()
// []enu.Tuple2[string, error]{
// {"", errors.New("some error")},
// {"https://amazon.co.jp", nil},
// {"https://google.com", nil},
// }
This package provides the below Enumerables:
- Enumerable[T any]
- ComparerEnumerable[T comparable]
- MapEnumerable[K comparable, V any]
- NumericEnumerable[T constraints.Float | constraints.Integer]
- OrderedEnumerable[T constraints.Ordered]
These allow for a common interface and operations specific to each collection.
When you impelement Enumearble, you must also impelement IEnumerable[T] interface.
Required to use the functions in this package.
The basic implementations are provided by this package.
This package provides the blow enumerators:
- RangeEnumerator
- NumericRangeEnumerator
- DateRangeEnumerator
- Generator
- ChannelEnumerator
- FileEnumerator
When you impelement Enumerator, you must also impelement IEnumerator[T] interface.
Interfaces to Enumerable[T]
.
Implementing this method allows to use the Enumerable functions.
The basic Enumerable implementations are provided by this package.
// IEnumerable[T any] is an interface for using Enumerable functions.
type IEnumerable[T any] interface {
// GetEnumerator returns IEnumerator[T] .
GetEnumerator() IEnumerator[T]
}
Interfaces to Enumerator[T]
.
// IEnumerator[T any] supports iteration over a generic collection.
type IEnumerator[T any] interface {
// Next returns a next item of collection. If Next passes the end of the collection, the empty item and true.
Next() (T, bool)
// Dispose disposes the managed resources in the collection.
// This method called when the iteration is completed.
Dispose()
}
ErrorProvider supports iteration error. If an Enumerable raises an error during execution of Next() or Dispose(), implement this interface.
type ErrorProvider interface {
// Err returns error during execution of Next() or Dispose()
// If you want to retrieve this error, you can do so in the following way.
Err() error
}
If you want to retrieve this error, you can do so in the following way.
e := enu.FromFile("/path/to/notfound/file")
r := e.ToSlice()
if err := e.Err(); err != nil {
panic(err)
}
// or
e := enu.FromFile("/path/to/notfound/file")
var result []string
if err := e.Result(&result).Err(); err != nil {
panic(err)
}
Interface to RangeEnumerator
.
type RangeValuer[T1, T2 any] interface {
// Compare self and other
Compare(T1) int
// Returns current value.
Value() T1
// Returns Next RangeValuer
Next(step T2) RangeValuer[T1, T2]
}
Enumerable
supports generic type of [T any]
.
ComparerEnumerable
supports generic type of [T comparable]
.
MapEnumerable
supports generic type of [K comparable, V any]
.
NumericEnumerable
supports generic type of [T constraints.Integer | constraints.Float]
.
OrderedEnumerable
supports generic type of [T constraints.Ordered]
.
- Each[T any]
- ToSlice[T any]
- Result[T any]
- Err
- Count[T any]
- Filter[T any]
- Reject[T any]
- Nth[T any]
- Find[T any]
- First[T any]
- Last[T any]
- Reverse[T any]
- Sort[T any] only supported below:
- SortBy[T any]
- IsAll[T any]
- IsAny[T any]
- Take[T any]
- ToMap[T any]
- Uniq only supported below:
- Contains only supported below:
- IndexOf only supported below:
- Min only supported below:
- Max only supported below:
- Sum only supported below:
- Keys only supported below:
- Values only supported below:
- GetEnumerator
RangeEnumerator
is basic range enumerator for
Implements RangeValuer
interface if you want custom range.
NumericRangeEnumerator
is range enumerator for constraints.Integer
and constraints.Float
.
DateRangeEnumerator
is range enumerator for time.Time
with time.Duration
.
Generator
provides generator pattern from func.
ChannelEnumerator
is enumerator for chan(T)
.
And see the concurrent functions.
FileEnumerator
is enumerator for file .
Returns an *Enumerable[T]
with IEnumerator
argument.
enumerator := enu.NewSliceEnumerator([]int{1, 2, 3})
r := enu.New(enumerator).Count()
// 3
Returns an *Enumerator[T]
with slice
argument.
r := enu.From([]int{1, 2, 3}).Count()
// 3
Returns an *Enumerator[T]
with IEnumerable[T]
argument.
// each enumerables implements IEnumerable[T]
var e IEnumerable[int] = enu.FromComparable([]int{1, 1, 2, 3, 3})
// use generic methods
r := enu.To(e).ToSlice()
// []int{1, 1, 2, 3, 3}
Returns an *Enumerator[T]
with chan(T)
argument.
ch := make(chan (int))
go func() {
defer close(ch)
for i := 1; i < 6; i++ {
ch <- i
}
}()
r := enu.FromChannel(ch).ToSlice()
// []int{1, 2, 3, 4, 5}
Returns an *Enumerator[T]
with string of filepath argument.
f, err := os.CreateTemp(os.TempDir(), "enu-filetest-")
if err != nil {
t.Fatal(err)
}
for _, s := range []string{"foo\n", "bar\n", "baz"} {
if _, err = f.Write([]byte(s)); err != nil {
t.Fatal(err)
}
}
reader := enu.FromFile(f.Name())
// Capture error from Err()
err := reader.Each(func(line string, index int) {
log.Printf("line%d: %s", index, line)
}).Err()
var result []string
if err := reader.Result(&result).Err(); err != nil {
panic(err)
}
r1 := reader.ToSlice()
// []string{"foo", "bar", "baz"}
err1 := reader.Err()
// nil
if err := os.Remove(f.Name()); err != nil {
t.Fatal(err)
}
r2 := reader.ToSlice()
// []string{}
err2 := reader.Err()
// no such file or directory
Returns an *ComparerEnumerable[T]
with comparable
argument.
r := enu.FromComparable([]int{1, 1, 2, 3, 3}).Uniq().ToSlice()
// []int{1, 2, 3}
Returns an *ComparerEnumerable[T]
with IEnumerable[T comparable]
argument.
// Enumerable[T] does not implement Uniq()
e := enu.From([]int{1, 1, 2, 3, 3})
// Convert to `ComparerEnumerable` to be use.
r := enu.ToComparable(e).Uniq().ToSlice()
// []int{1, 2, 3}
Returns an *MapEnumerable[K, V]
with map[K]V
argument.
r := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Keys()
// []int{1, 2, 3}
Returns an *MapEnumerable[T]
with IEnumerable[KeyValuePair[K, V]]
argument.
// `Enumerable` does not impelements `Keys()`
e := enu.From([]enu.KeyValuePair[int, string]{
{Key: 1, Value: "foo"},
{Key: 2, Value: "bar"},
{Key: 3, Value: "baz"},
})
// Convert to `MapEnumerable`
r := enu.ToMap(e).Keys()
// []int{1, 2, 3}
Returns an *NumericEnumerable[T]
with constraints.Integer
or constraints.Float
argument.
r := enu.FromNumeric([]int{1, 2, 3}).Sum()
// 6
Returns an *NumericEnumerable[T]
with IEnumerable[T constraints.Integer | constraints.Float]
argument.
// `Enumerable` does not implement `Sum()`
e := enu.From([]int{1, 2, 3})
// Convert to `NumericEnumerable`
r := enu.ToNumeric(e).Sum()
// 6
Returns an *OrderedEnumerable[T]
with constraints.Ordered
argument.
r := enu.FromOrdered([]string{"c", "a", "b"}).Sort()
// //[]string{"a", "b", "c"}
Returns an *OrderedEnumerable[T]
with IEnumerable[T constraints.Ordered]
argument.
// `Enumerable` does not implement `Sum()`
e := enu.From([]string{"c", "a", "b"})
// Convert to `NumericEnumerable`
r := enu.ToNumeric(e).Sum()
// 6
Every enumerable functions have lazy
keyword.
If the lazy
keyword is true, then calling the function will immediately evaluate the Enumerable by the previously called Queryies.
example:
// Filter is lazy. The collection does not iterated at here.
e := enu.From([]int{1, 2, 3}).Filter(func(item, index int) bool {
return item % 2 == 0
})
// The collection iterate immediately.
r := e.ToSlice()
Also, the Query returns a new Enumereable. This supports intuitive iteration of collections.
example:
// Filter is lazy. The collection does not iterated at here.
e := enu.From([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}).Filter(func(item, index int) bool {
return item % 2 == 0
})
r1 := e.Take(5)
// []int{2, 4, 6, 8, 10}
r2 := e.Take(5)
// []int{2, 4, 6, 8, 10}
However that these behaviors vary depending on the Enumerator.
For example, ChannelEnumerator
which handles streams from chan(T)
behaves as belows:
ch := make(chan (int))
go func() {
for i := 1; i < 6; i++ {
ch <- i
}
}()
stream := enu.FromChannel(ch)
r1 := stream.Take(3).ToSlice()
// []int{1, 2, 3}
r2 := stream.Take(1).ToSlice()
// []int{4}
- lazy: false
- supported: all
Iterates over elements of a collection and invokes the function over each element.
enu.From([]string{"hello", "world"}).Each(func(x string, _ int) {
println(x)
})
// prints "hello\nworld\n"
- lazy: false
- supported: all
Transform a enumerable into a slice.
r1 := enu.From([]int{1, 2, 3}).ToSlice()
// []int{1, 2, 3}
r2 := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz"}).ToSlice()
// []enu.KeyValuePair[int, string]{{Key: 1, Value: "foo"}, {Key: 2, Value: "bar"}, {Key: 3, Value: "baz"}}
- lazy: false
- supported: all
Transform a enumerable into a slice and write to given ptr.
e := enu.From([]int{1, 2, 3, 4, 5}).Reject(func(i, _ int) bool { return i%2 == 0 })
var result []int
e.Result(&result)
// []int{1, 3, 5}
- supported: all
Retrieves errors that occurred during the execution of the Enumerator.
This error is returned only when the Enumerator implements ErrorProvider.
type errorE struct {
err error
}
func (e *errorE) Dispose() {}
func (e *errorE) Next() (bool, bool) {
e.err = errors.New("error cause")
return false, false
}
// Implements ErrorProvider interface
func (e *errorE) Err() error { return e.err }
e := enu.New[bool](&errorE{})
err := e.Err()
// nil
r, ok := e.First()
// false, false
err = e.Err()
// error cause
- lazy: false
- supported: all
Counts the number of elements in the collection.
r1 := enu.From([]int{1, 2, 3, 4, 5}).Count()
// 5
r := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Count()
// 3
- lazy: true
- supported: all
Counts the number of elements in the collection.
r1 := enu.From([]int{1, 2, 3, 4}).Filter(func(x int, index int) bool {
return x%2 == 0
}).ToSlice()
// []int{2, 4}
r2 := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz", 4: "boo"}).Filter(func(kv enu.KeyValuePair[int, string], _ int) bool {
return kv.Key%2 == 0
}).ToMap()
// map[int]string{2: "bar", 4: "boo"}
- lazy: true
- supported: all
The opposite of Filter, this method returns the elements of collection that predicate does not return truthy for.
r1 := enu.From([]int{1, 2, 3, 4}).Reject(func(x int, index int) bool {
return x%2 == 0
}).ToSlice()
// []int{1, 3}
r2 := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz", 4: "boo"}).Reject(func(kv enu.KeyValuePair[int, string], _ int) bool {
return kv.Key%2 == 0
}).ToMap()
// map[int]string{1: "foo", 3: "baz"}
- lazy: false
- supported: all
Returns the element at index nth of collection. If nth is negative, the nth element from the end is returned. An false is returned when nth is out of slice bounds.
nth, ok := enu.New([]int{0, 1, 2, 3}).Nth(2)
// 2, true
nth, ok := enu.New([]int{0, 1, 2, 3}).Nth(-2)
// 2, true
nth, ok := enu.New([]int{0, 1, 2, 3}).Nth(6)
// 0, false
- lazy: false
- supported: all
Search an element in a slice based on a predicate. It returns element and true if element was found.
slices := enu.From([]int{1, 2, 3, 4, 5})
r1, ok := slices.Find(func(item, _ int) bool {
return item%2 == 0
})
// 2, true
_, ok = slices.Find(func(item, _ int) bool {
return item > 10
})
// 0, false
r2, ok := slices.Find(func(_, index int) bool {
return index == 3
})
// 4, true
ch := make(chan (int))
defer close(ch)
go func() {
for i := 1; i < 6; i++ {
ch <- i
}
}()
r3, ok := enu.FromChannel(ch).Find(func(i int) bool {
return i == 3
})
// 3, true
- lazy: false
- supported: all
Search a first element in a slice based. It returns element and true if collection was not empty.
r1, ok := enu.From([]int{1, 2, 3, 4, 5}).First()
// 1, true
r2, ok := enu.From([]int{}).First()
// 0, false
- lazy: false
- supported: all
Search a last element in a slice based. It returns element and true if collection was not empty.
r1, ok := enu.From([]int{1, 2, 3, 4, 5}).Last()
// 5, true
r2, ok := enu.From([]int{}).Last()
// 0, false
- lazy: false
- supported: all
Reverses array so that the first element becomes the last, the second element becomes the second to last, and so on.
r := enu.From([]int{1, 2, 3, 4, 5}).Reverse().ToSlice()
// []int{5, 4, 3, 2, 1}
- lazy: false
- supported only:
- NumericEnumerable
- OrderedEnumerable
Sorts the slice x using res[i] < res[j]
, keeping equal elements in their original order.
r := enu.From([]int{5, 3, 2, 1, 4}).Sort().ToSlice()
// []int{1, 2, 3, 4, 5}
- lazy: false
- supported: all
SortBy the slice x using the provided less function, keeping equal elements in their original order.
r := enu.From([]string{"aa", "bbb", "c"}).SortBy(func(i, j string) bool {
return len(i) > len(j)
}).ToSlice()
// []string{"bbb", "aa", "c"}
- lazy: false
- supported: all
Returns true if all elements meet a specified criterion; false otherwise.
IsAll
the slice x using the provided less function, keeping equal elements in their original order.
If a first negative item is found, it stops iteration and does not look into remaining groups.
r := enu.From([]int{1, 1, 1, 1, 1}).IsAll(func(item int) bool { return item == 1 })
// true
r2 := enu.From([]int{1, 2, 1, 1, 1}).IsAll(func(item int) bool { return item == 1 })
// false
- lazy: false
- supported: all
Returns true if any elements meet a specified criterion; false otherwise.
IsAll the slice x using the provided less function, keeping equal elements in their original order.
If a first positive item is found, it stops iteration and does not look into remaining groups.
r1 := enu.From([]int{1, 1, 1, 1, 1}).IsAny(func(item int) bool { return item == 2 })
// false
r2 := enu.From([]int{1, 2, 1, 1, 1}).IsAny(func(item int) bool { return item == 2 })
// true
- lazy: true
- supported: all
Returns a specified number of leading elements.
This works lazily. If a number of leading item is found, it stops iteration and does not look into remaining groups.
r1 := enu.From([]int{1, 2, 3, 4, 5}).Take(3).ToSlice()
// []int{1, 2, 3}
r2 := enu.FromNumericRange(1, math.MaxInt).Take(10).ToSlice()
// []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
- lazy: false
- supported: all
Returns a map key-value pairs provided by index and value of slice.
If receiver is MapEnumerable
, returns map provided by KeyValuePair
.
r1 := enu.From([]int{3, 2, 1}).ToMap()
// map[int]int{0: 3, 1: 2, 2: 1}
r2 := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz", 4: "boo"}).Filter(func(kv enu.KeyValuePair[int, string], _ int) bool {
return kv.Key%2 == 0
}).ToMap()
// map[int]string{2: "bar", 4: "boo"}
- lazy: true
- supported: only
- ComparerEnumerable
- NumericEnumerable
- OrderedEnumerable
Returns elements that are not duplicates.
r := enu.FromComparable([]int{1, 1, 2, 3, 3}).Uniq().ToSlice()
// []int{1, 2, 3}
- lazy: false
- supported: only
- ComparerEnumerable
- NumericEnumerable
- OrderedEnumerable
Returns true if an element is present in a collection.
r1 := enu.FromComparable([]int{1, 1, 2, 3, 3}).Contains(1)
// true
r2 := enu.FromComparable([]int{1, 1, 2, 3, 3}).Contains(4)
// false
- lazy: false
- supported: only
- ComparerEnumerable
- NumericEnumerable
- OrderedEnumerable
Returns the index at which the first occurrence of a value is found in an array or return -1 if the value cannot be found.
r1 := enu.FromComparable([]int{1, 1, 2, 3, 3}).IndexOf(2)
// 2
r2 := enu.FromComparable([]int{1, 1, 2, 3, 3}).IndexOf(4)
// -1
- lazy: false
- supported: only
- OrderedEnumerable
- NumericEnumerable
Search the minimum value of a collection.
Returns zero value when collection is empty.
r1 := enu.FromOrdered([]int{2, 1, 3}).Min()
// 1
r2 := enu.FromOrdered([]int{}).Min()
// 0
- lazy: false
- supported: only
- OrderedEnumerable
- NumericEnumerable
Search the maximum value of a collection.
Returns zero value when collection is empty.
r1 := enu.FromOrdered([]int{2, 1, 3}).Max()
// 3
r2 := enu.FromOrdered([]int{}).Max()
// 0
- lazy: false
- supported: only
- NumericEnumerable
Sums the values in a collection.
If collection is empty 0 is returned.
r1 := enu.FromNumeric([]int{2, 1, 3}).Sum()
// 6
r2 := enu.FromNumeric([]int{}).Sum()
// 0
- lazy: false
- supported: only
- MapEnumerable
Returns an array of the map keys.
r := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Keys()
// []int{1, 2, 3}
- lazy: false
- supported: only
- MapEnumerable
Returns an array of the map values.
r := enu.FromMap(map[int]string{1: "foo", 2: "bar", 3: "baz"}).Values()
// []string{"foo", "bar", "baz"}
- lazy: true
- supported: all
Returns IEnumerator[T]
.
// Example: `ToNumeric` only supports `*Enumerator[T any]` , but enu.FromOrdered returns EnumeratorOrderd
// Get `IEnumreator[T any]` if GetEnumerator to use.
enumerator := enu.FromOrdered([]int{1, 2, 3}).GetEnumerator()
r := enu.ToNumeric[int](enumerator).Sum()
// 6
Returns *Enumerator[T any]
with *RangeEnumerator[T1, T2]
argument.
Expects range values impelements RangeValuer interface.
type Month time.Month
// Next returns next month.
func (m Month) Next(step int) enu.RangeValuer[time.Month, int] {
val := int(m) + step
if val > 12 {
val -= 12
}
return Month(val)
}
// Value returns current month.
func (m Month) Value() time.Month {
return time.Month(m)
}
// Compare current and other elements
func (m Month) Compare(other time.Month) int {
if int(m) < int(other) {
return -1
}
if int(m) > int(other) {
return 1
}
return 0
}
r1 := enu.FromRange[time.Month, int](Month(time.January), Month(time.July), 1).ToSlice()
// []time.Month{time.January, time.February, time.March, time.April, time.May, time.June, time.July}
r2 := enu.FromRange[time.Month, int](Month(time.January), Month(math.MaxInt), 1).Take(13).ToSlice()
// []time.Month{
// time.January,
// time.February,
// time.March,
// time.April,
// time.May,
// time.June,
// time.July,
// time.August,
// time.September,
// time.October,
// time.November,
// time.December,
// time.January,
// }
Returns an *NumericEnumerable[T]
with min
and max
argument.
If min
greater than max
empty range is returned.
r1 := enu.FromNumericRange(1, 5).ToSlice()
// []int{1, 2, 3, 4, 5}
r2 := enu.FromNumericRange(-5, -1).ToSlice()
// []int{-5, -4, -3, -2, -1}
r3 := enu.FromNumericRange(-1, -5).ToSlice()
// []int{}
r4 := enu.FromNumericRange(1, math.MaxInt).Take(10).ToSlice()
// []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
r5 := enu.FromNumericRange(1, math.Inf(0)).Take(3).ToSlice()
// []float64{1, 2, 3}
Returns an *NumericEnumerable[T]
with min
, max
and step
argument.
If min
greater than max
empty range is returned.
r1 := enu.FromNumericRangeWithStep(1, 5, 1).ToSlice()
// []int{1, 2, 3, 4, 5}
r2 := enu.FromNumericRangeWithStep(1.1, 5.1, 1.0).ToSlice()
// []float64{1.1, 2.1, 3.1, 4.1, 5.1}
Returns an *Enumerator[T]
with start
, end
and duration
argument.
If start
greater than end
empty range is returned.
r1 := enu.FromDateRange(
time.Date(2023, 5, 20, 21, 59, 59, 0, time.UTC),
time.Date(2023, 5, 20, 23, 59, 59, 0, time.UTC),
time.Hour,
).ToSlice()
// []time.Time{
// time.Date(2023, 5, 20, 21, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 20, 22, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 20, 23, 59, 59, 0, time.UTC),
// }
r2 := enu.FromDateRange(
time.Date(2023, 5, 20, 21, 59, 59, 0, time.UTC),
time.Date(2099, 5, 23, 21, 59, 59, 0, time.UTC),
time.Hour*24,
).Take(5).ToSlice()
// []time.Time{
// time.Date(2023, 5, 20, 21, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 21, 21, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 22, 21, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 23, 21, 59, 59, 0, time.UTC),
// time.Date(2023, 5, 24, 21, 59, 59, 0, time.UTC),
// }
Returns an *Enumerator[T]
with func(index int) (T, bool)
func.
fibonacci := func() func(int) (int, bool) {
n, n1 := 0, 1
return func(_ int) (int, bool) {
v := n
n, n1 = n1, n+n1
return v, true
}
}
g := enu.FromFunc(fibonacci())
r1, ok := g.First()
// 0, true
r2 := g.Take(10).ToSlice()
// []int{0, 1, 1, 2, 3, 5, 8, 13, 21, 34}
Executes a number of repeated functions in a goroutine and returns the result in channel.
mockHttpRequest := func(n int) enu.Tuple2[string, error] {
if n%2 == 0 {
return enu.Tuple2[string, error]{"OK", nil}
}
return enu.Tuple2[string, error]{"", errors.New("some error")}
}
// Aggregate function result by repeat and async
r := enu.FromChannel(enu.Repeat(2, 5, mockHttpRequest)).ToSlice()
// []enu.Tuple2[string, error]{
// {"OK", nil},
// {"OK", nil},
// {"OK", nil},
// {"", errors.New("some error")},
// {"", errors.New("some error")},
// }
Executes a multiple functions in a goroutine and returns the result in channel.
request1 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"https://google.com", nil}
}
request2 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"https://amazon.co.jp", nil}
}
request3 := func() enu.Tuple2[string, error] {
return enu.Tuple2[string, error]{"", errors.New("some error")}
}
// Aggregate multiple function result by async
r := enu.FromChannel(enu.Parallel(2, request1, request2, request3)).ToSlice()
// []enu.Tuple2[string, error]{
// {"", errors.New("some error")},
// {"https://amazon.co.jp", nil},
// {"https://google.com", nil},
// }
Executes a retryable functions in a goroutine while to succeeded, and returns the result in channel.
mockHttpRequest := func(n int) (string, error) {
if n < 5 {
n += 1
return "", errors.New("some error")
}
return "OK", nil
}
// Returns [result[T], true] if function was succeed.
r1, ok := enu.FromChannel(enu.Retry(3, 5, mockHttpRequest)).First()
// {"ok", true}, true
// Returns [empty[T], false] if function was failed with reach to maxRetry.
r2, ok := enu.FromChannel(enu.Retry(3, 3, mockHttpRequest)).First()
// {"", false}, true
Manipulates a slice of one type and transforms it into a slice of another type:
Reduces a collection to a single value.