doc: adding go playground examples

This commit is contained in:
Samuel Berthe
2025-09-23 14:54:30 +02:00
parent 9c8308ffda
commit 3bc887c57c
18 changed files with 249 additions and 17 deletions

View File

@@ -392,6 +392,8 @@ lop.Map([]int64{1, 2, 3, 4}, func(x int64, _ int) string {
// []string{"1", "2", "3", "4"} // []string{"1", "2", "3", "4"}
``` ```
[[play](https://go.dev/play/p/sCJaB3quRMC)]
Mutable: like `lo.Map()`, but the slice is updated in place. Mutable: like `lo.Map()`, but the slice is updated in place.
```go ```go
@@ -404,6 +406,8 @@ lom.Map(list, func(x int) int {
// []int{2, 4, 6, 8} // []int{2, 4, 6, 8}
``` ```
[[play](https://go.dev/play/p/0jY3Z0B7O_5)]
### UniqMap ### UniqMap
Manipulates a slice and transforms it to a slice of another type with unique values. Manipulates a slice and transforms it to a slice of another type with unique values.
@@ -421,6 +425,8 @@ names := lo.UniqMap(users, func(u User, index int) string {
// []string{"Alex", "Bob", "Alice"} // []string{"Alex", "Bob", "Alice"}
``` ```
[[play](https://go.dev/play/p/fygzLBhvUdB)]
### FilterMap ### FilterMap
Returns a slice which obtained after both filtering and mapping using the given callback function. Returns a slice which obtained after both filtering and mapping using the given callback function.
@@ -616,6 +622,8 @@ groups := lo.GroupByMap([]int{0, 1, 2, 3, 4, 5}, func(i int) (int, int) {
// map[int][]int{0: []int{0, 6}, 1: []int{2, 8}, 2: []int{4, 10}} // map[int][]int{0: []int{0, 6}, 1: []int{2, 8}, 2: []int{4, 10}}
``` ```
[[play](https://go.dev/play/p/iMeruQ3_W80)]
### Chunk ### Chunk
Returns an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements. Returns an array of elements split into groups the length of size. If array can't be split evenly, the final chunk will be the remaining elements.
@@ -634,7 +642,7 @@ lo.Chunk([]int{0}, 2)
// [][]int{{0}} // [][]int{{0}}
``` ```
[[play](https://go.dev/play/p/EeKl0AuTehH)] [[play](https://go.dev/play/p/kEMkFbdu85g)]
### PartitionBy ### PartitionBy
@@ -853,6 +861,8 @@ result := lo.FilterSliceToMap(list, func(str string) (string, int, bool) {
// map[string][int]{"aa":2 "aaa":3} // map[string][int]{"aa":2 "aaa":3}
``` ```
[[play](https://go.dev/play/p/2z0rDz2ZSGU)]
### Keyify ### Keyify
Returns a map with each unique element of the slice as a key. Returns a map with each unique element of the slice as a key.
@@ -862,6 +872,8 @@ set := lo.Keyify([]int{1, 1, 2, 3, 4})
// map[int]struct{}{1:{}, 2:{}, 3:{}, 4:{}} // map[int]struct{}{1:{}, 2:{}, 3:{}, 4:{}}
``` ```
[[play](https://go.dev/play/p/RYhhM_csqIG)]
### Drop ### Drop
Drops n elements from the beginning of a slice or array. Drops n elements from the beginning of a slice or array.
@@ -1360,7 +1372,7 @@ entries := lo.Entries(map[string]int{"foo": 1, "bar": 2})
// } // }
``` ```
[[play](https://go.dev/play/p/3Dhgx46gawJ)] [[play](https://go.dev/play/p/_t4Xe34-Nl5)]
### FromEntries (alias: FromPairs) ### FromEntries (alias: FromPairs)
@@ -1678,6 +1690,8 @@ mean := lo.MeanBy([]float64{}, mapper)
// 0 // 0
``` ```
[[play](https://go.dev/play/p/j7TsVwBOZ7P)]
### Mode ### Mode
@@ -1773,7 +1787,7 @@ str := lo.PascalCase("hello_world")
// HelloWorld // HelloWorld
``` ```
[[play](https://go.dev/play/p/iZkdeLP9oiB)] [[play](https://go.dev/play/p/Dy_V_6DUYhe)]
### CamelCase ### CamelCase
@@ -1784,7 +1798,7 @@ str := lo.CamelCase("hello_world")
// helloWorld // helloWorld
``` ```
[[play](https://go.dev/play/p/dtyFB58MBRp)] [[play](https://go.dev/play/p/Go6aKwUiq59)]
### KebabCase ### KebabCase
@@ -1795,7 +1809,7 @@ str := lo.KebabCase("helloWorld")
// hello-world // hello-world
``` ```
[[play](https://go.dev/play/p/2YTuPafwECA)] [[play](https://go.dev/play/p/96gT_WZnTVP)]
### SnakeCase ### SnakeCase
@@ -1806,7 +1820,7 @@ str := lo.SnakeCase("HelloWorld")
// hello_world // hello_world
``` ```
[[play](https://go.dev/play/p/QVKJG9nOnDg)] [[play](https://go.dev/play/p/ziB0V89IeVH)]
### Words ### Words
@@ -1817,7 +1831,7 @@ str := lo.Words("helloWorld")
// []string{"hello", "world"} // []string{"hello", "world"}
``` ```
[[play](https://go.dev/play/p/2P4zhqqq61g)] [[play](https://go.dev/play/p/-f3VIQqiaVw)]
### Capitalize ### Capitalize
@@ -1828,6 +1842,8 @@ str := lo.Capitalize("heLLO")
// Hello // Hello
``` ```
[[play](https://go.dev/play/p/uLTZZQXqnsa)]
### Ellipsis ### Ellipsis
Trims and truncates a string to a specified length in `bytes` and appends an ellipsis if truncated. If the string contains non-ASCII characters (which may occupy multiple bytes in UTF-8), truncating by byte length may split a character in the middle, potentially resulting in garbled output. Trims and truncates a string to a specified length in `bytes` and appends an ellipsis if truncated. If the string contains non-ASCII characters (which may occupy multiple bytes in UTF-8), truncating by byte length may split a character in the middle, potentially resulting in garbled output.
@@ -1843,6 +1859,8 @@ str := lo.Ellipsis("Lorem Ipsum", 3)
// ... // ...
``` ```
[[play](https://go.dev/play/p/qE93rgqe1TW)]
### T2 -> T9 ### T2 -> T9
Creates a tuple from a list of values. Creates a tuple from a list of values.
@@ -1968,6 +1986,8 @@ duration := lo.Duration(func() {
// 3s // 3s
``` ```
[[play](https://go.dev/play/p/HQfbBbAXaFP)]
### Duration0 -> Duration10 ### Duration0 -> Duration10
Returns the time taken to execute a function. Returns the time taken to execute a function.
@@ -2028,6 +2048,8 @@ for i := range children {
} }
``` ```
[[play](https://go.dev/play/p/UZGu2wVg3J2)]
Many distributions strategies are available: Many distributions strategies are available:
- [lo.DispatchingStrategyRoundRobin](./channel.go): Distributes messages in a rotating sequential manner. - [lo.DispatchingStrategyRoundRobin](./channel.go): Distributes messages in a rotating sequential manner.
@@ -2088,6 +2110,8 @@ for v := range lo.SliceToChannel(2, list) {
// prints 1, then 2, then 3, then 4, then 5 // prints 1, then 2, then 3, then 4, then 5
``` ```
[[play](https://go.dev/play/p/lIbSY3QmiEg)]
### ChannelToSlice ### ChannelToSlice
Returns a slice built from channels items. Blocks until channel closes. Returns a slice built from channels items. Blocks until channel closes.
@@ -2274,6 +2298,8 @@ present := lo.Contains([]int{0, 1, 2, 3, 4, 5}, 5)
// true // true
``` ```
[[play](https://go.dev/play/p/W1EvyqY6t9j)]
### ContainsBy ### ContainsBy
Returns true if the predicate function returns `true`. Returns true if the predicate function returns `true`.
@@ -2308,6 +2334,8 @@ b := EveryBy([]int{1, 2, 3, 4}, func(x int) bool {
// true // true
``` ```
[[play](https://go.dev/play/p/dn1-vhHsq9x)]
### Some ### Some
Returns true if at least 1 element of a subset is contained into a collection. Returns true if at least 1 element of a subset is contained into a collection.
@@ -2316,6 +2344,9 @@ If the subset is empty Some returns false.
```go ```go
ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{0, 6}) ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{0, 6})
// true // true
```
[[play](https://go.dev/play/p/Lj4ceFkeT9V)]
ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6})
// false // false
@@ -2344,6 +2375,8 @@ b := None([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6})
// true // true
``` ```
[[play](https://go.dev/play/p/fye7JsmxzPV)]
### NoneBy ### NoneBy
Returns true if the predicate returns true for none of the elements in the collection or if the collection is empty. Returns true if the predicate returns true for none of the elements in the collection or if the collection is empty.
@@ -2355,6 +2388,8 @@ b := NoneBy([]int{1, 2, 3, 4}, func(x int) bool {
// true // true
``` ```
[[play](https://go.dev/play/p/O64WZ32H58S)]
### Intersect ### Intersect
Returns the intersection between two collections. Returns the intersection between two collections.
@@ -2385,6 +2420,8 @@ left, right := lo.Difference([]int{0, 1, 2, 3, 4, 5}, []int{0, 1, 2, 3, 4, 5})
// []int{}, []int{} // []int{}, []int{}
``` ```
[[play](https://go.dev/play/p/pKE-JgzqRpz)]
### Union ### Union
Returns all distinct elements from given collections. Result will not change the order of elements relatively. Returns all distinct elements from given collections. Result will not change the order of elements relatively.
@@ -2499,6 +2536,8 @@ notFound := lo.IndexOf([]int{0, 1, 2, 1, 2, 3}, 6)
// -1 // -1
``` ```
[[play](https://go.dev/play/p/Eo7W0lvKTky)]
### LastIndexOf ### LastIndexOf
Returns the index at which the last occurrence of a value is found in an array or return -1 if the value cannot be found. Returns the index at which the last occurrence of a value is found in an array or return -1 if the value cannot be found.
@@ -2527,6 +2566,8 @@ str, ok := lo.Find([]string{"foobar"}, func(i string) bool {
// "", false // "", false
``` ```
[[play](https://go.dev/play/p/Eo7W0lvKTky)]
### FindIndexOf ### FindIndexOf
FindIndexOf searches an element in a slice based on a predicate and returns the index and true. It returns -1 and false if the element is not found. FindIndexOf searches an element in a slice based on a predicate and returns the index and true. It returns -1 and false if the element is not found.
@@ -2543,6 +2584,8 @@ str, index, ok := lo.FindIndexOf([]string{"foobar"}, func(i string) bool {
// "", -1, false // "", -1, false
``` ```
[[play](https://go.dev/play/p/XWSEM4Ic_t0)]
### FindLastIndexOf ### FindLastIndexOf
FindLastIndexOf searches an element in a slice based on a predicate and returns the index and true. It returns -1 and false if the element is not found. FindLastIndexOf searches an element in a slice based on a predicate and returns the index and true. It returns -1 and false if the element is not found.
@@ -2559,6 +2602,8 @@ str, index, ok := lo.FindLastIndexOf([]string{"foobar"}, func(i string) bool {
// "", -1, false // "", -1, false
``` ```
[[play](https://go.dev/play/p/dPiMRtJ6cUx)]
### FindOrElse ### FindOrElse
Search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise. Search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise.
@@ -2666,6 +2711,8 @@ min := lo.Min([]time.Duration{time.Second, time.Hour})
// 1s // 1s
``` ```
[[play](https://go.dev/play/p/r6e-Z8JozS8)]
### MinIndex ### MinIndex
Search the minimum value of a collection and the index of the minimum value. Search the minimum value of a collection and the index of the minimum value.
@@ -2985,6 +3032,8 @@ lo.Sample([]string{})
// "" // ""
``` ```
[[play](https://go.dev/play/p/FYA45LcpfM2)]
### SampleBy ### SampleBy
@@ -3215,6 +3264,8 @@ ptr := lo.ToPtr("hello world")
// *string{"hello world"} // *string{"hello world"}
``` ```
[[play](https://go.dev/play/p/P2sD0PMXw4F)]
### Nil ### Nil
Returns a nil pointer of type. Returns a nil pointer of type.
@@ -3503,6 +3554,8 @@ f(42)
// 47 // 47
``` ```
[[play](https://go.dev/play/p/Sy1gAQiQZ3v)]
### Partial2 -> Partial5 ### Partial2 -> Partial5
Returns new function that, when called, has its first argument set to the provided value. Returns new function that, when called, has its first argument set to the provided value.
@@ -3518,6 +3571,8 @@ f(42, -4)
// 80 // 80
``` ```
[[play](https://go.dev/play/p/-xiPjy4JChJ)]
### Attempt ### Attempt
Invokes a function N times until it returns valid output. Returns either the caught error or nil. Invokes a function N times until it returns valid output. Returns either the caught error or nil.
@@ -3606,7 +3661,7 @@ count1, err1 := lo.AttemptWhile(5, func(i int) (error, bool) {
For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff). For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
[[play](https://go.dev/play/p/M2wVq24PaZM)] [[play](https://go.dev/play/p/1VS7HxlYMOG)]
### AttemptWhileWithDelay ### AttemptWhileWithDelay
@@ -3631,7 +3686,7 @@ count1, time1, err1 := lo.AttemptWhileWithDelay(5, time.Millisecond, func(i int,
For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff). For more advanced retry strategies (delay, exponential backoff...), please take a look on [cenkalti/backoff](https://github.com/cenkalti/backoff).
[[play](https://go.dev/play/p/cfcmhvLO-nv)] [[play](https://go.dev/play/p/mhufUjJfLEF)]
### Debounce ### Debounce
@@ -3876,6 +3931,8 @@ iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, 5*time.Mi
// false // false
``` ```
[[play](https://go.dev/play/p/t_wTDmubbK3)]
### WaitForWithContext ### WaitForWithContext
Runs periodically until a condition is validated or context is invalid. Runs periodically until a condition is validated or context is invalid.
@@ -3918,6 +3975,8 @@ iterations, duration, ok := lo.WaitForWithContext(expiringCtx, alwaysFalse, 100*
// false // false
``` ```
[[play](https://go.dev/play/p/t_wTDmubbK3)]
### Validate ### Validate
Helper function that creates an error when a condition is not met. Helper function that creates an error when a condition is not met.

View File

@@ -14,6 +14,7 @@ type DispatchingStrategy[T any] func(msg T, index uint64, channels []<-chan T) i
// ChannelDispatcher distributes messages from input channels into N child channels. // ChannelDispatcher distributes messages from input channels into N child channels.
// Close events are propagated to children. // Close events are propagated to children.
// Underlying channels can have a fixed buffer capacity or be unbuffered when cap is 0. // Underlying channels can have a fixed buffer capacity or be unbuffered when cap is 0.
// Play: https://go.dev/play/p/UZGu2wVg3J2
func ChannelDispatcher[T any](stream <-chan T, count int, channelBufferCap int, strategy DispatchingStrategy[T]) []<-chan T { func ChannelDispatcher[T any](stream <-chan T, count int, channelBufferCap int, strategy DispatchingStrategy[T]) []<-chan T {
children := createChannels[T](count, channelBufferCap) children := createChannels[T](count, channelBufferCap)
@@ -73,6 +74,7 @@ func channelIsNotFull[T any](ch <-chan T) bool {
// DispatchingStrategyRoundRobin distributes messages in a rotating sequential manner. // DispatchingStrategyRoundRobin distributes messages in a rotating sequential manner.
// If the channel capacity is exceeded, the next channel will be selected and so on. // If the channel capacity is exceeded, the next channel will be selected and so on.
// Play: https://go.dev/play/p/UZGu2wVg3J2
func DispatchingStrategyRoundRobin[T any](msg T, index uint64, channels []<-chan T) int { func DispatchingStrategyRoundRobin[T any](msg T, index uint64, channels []<-chan T) int {
for { for {
i := int(index % uint64(len(channels))) i := int(index % uint64(len(channels)))
@@ -87,6 +89,7 @@ func DispatchingStrategyRoundRobin[T any](msg T, index uint64, channels []<-chan
// DispatchingStrategyRandom distributes messages in a random manner. // DispatchingStrategyRandom distributes messages in a random manner.
// If the channel capacity is exceeded, another random channel will be selected and so on. // If the channel capacity is exceeded, another random channel will be selected and so on.
// Play: https://go.dev/play/p/GEyGn3TdGk4
func DispatchingStrategyRandom[T any](msg T, index uint64, channels []<-chan T) int { func DispatchingStrategyRandom[T any](msg T, index uint64, channels []<-chan T) int {
for { for {
i := rand.IntN(len(channels)) i := rand.IntN(len(channels))
@@ -100,6 +103,7 @@ func DispatchingStrategyRandom[T any](msg T, index uint64, channels []<-chan T)
// DispatchingStrategyWeightedRandom distributes messages in a weighted manner. // DispatchingStrategyWeightedRandom distributes messages in a weighted manner.
// If the channel capacity is exceeded, another random channel will be selected and so on. // If the channel capacity is exceeded, another random channel will be selected and so on.
// Play: https://go.dev/play/p/v0eMh8NZG2L
func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy[T] { func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy[T] {
seq := []int{} seq := []int{}
@@ -123,6 +127,7 @@ func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy
// DispatchingStrategyFirst distributes messages in the first non-full channel. // DispatchingStrategyFirst distributes messages in the first non-full channel.
// If the capacity of the first channel is exceeded, the second channel will be selected and so on. // If the capacity of the first channel is exceeded, the second channel will be selected and so on.
// Play: https://go.dev/play/p/OrJCvOmk42f
func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) int { func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) int {
for { for {
for i := range channels { for i := range channels {
@@ -136,6 +141,7 @@ func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) i
} }
// DispatchingStrategyLeast distributes messages in the emptiest channel. // DispatchingStrategyLeast distributes messages in the emptiest channel.
// Play: https://go.dev/play/p/ypy0jrRcEe7
func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) int { func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) int {
seq := Range(len(channels)) seq := Range(len(channels))
@@ -146,6 +152,7 @@ func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) i
// DispatchingStrategyMost distributes messages in the fullest channel. // DispatchingStrategyMost distributes messages in the fullest channel.
// If the channel capacity is exceeded, the next channel will be selected and so on. // If the channel capacity is exceeded, the next channel will be selected and so on.
// Play: https://go.dev/play/p/erHHone7rF9
func DispatchingStrategyMost[T any](msg T, index uint64, channels []<-chan T) int { func DispatchingStrategyMost[T any](msg T, index uint64, channels []<-chan T) int {
seq := Range(len(channels)) seq := Range(len(channels))
@@ -155,6 +162,7 @@ func DispatchingStrategyMost[T any](msg T, index uint64, channels []<-chan T) in
} }
// SliceToChannel returns a read-only channels of collection elements. // SliceToChannel returns a read-only channels of collection elements.
// Play: https://go.dev/play/p/lIbSY3QmiEg
func SliceToChannel[T any](bufferSize int, collection []T) <-chan T { func SliceToChannel[T any](bufferSize int, collection []T) <-chan T {
ch := make(chan T, bufferSize) ch := make(chan T, bufferSize)
@@ -170,6 +178,7 @@ func SliceToChannel[T any](bufferSize int, collection []T) <-chan T {
} }
// ChannelToSlice returns a slice built from channels items. Blocks until channel closes. // ChannelToSlice returns a slice built from channels items. Blocks until channel closes.
// Play: https://go.dev/play/p/lIbSY3QmiEg
func ChannelToSlice[T any](ch <-chan T) []T { func ChannelToSlice[T any](ch <-chan T) []T {
collection := []T{} collection := []T{}
@@ -181,6 +190,7 @@ func ChannelToSlice[T any](ch <-chan T) []T {
} }
// Generator implements the generator design pattern. // Generator implements the generator design pattern.
// Play: https://go.dev/play/p/lIbSY3QmiEg
func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T { func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T {
ch := make(chan T, bufferSize) ch := make(chan T, bufferSize)
@@ -198,6 +208,7 @@ func Generator[T any](bufferSize int, generator func(yield func(T))) <-chan T {
// Buffer creates a slice of n elements from a channel. Returns the slice and the slice length. // Buffer creates a slice of n elements from a channel. Returns the slice and the slice length.
// @TODO: we should probably provide an helper that reuse the same buffer. // @TODO: we should probably provide an helper that reuse the same buffer.
// Play: https://go.dev/play/p/gPQ-6xmcKQI
func Buffer[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) { func Buffer[T any](ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
buffer := make([]T, 0, size) buffer := make([]T, 0, size)
index := 0 index := 0
@@ -224,6 +235,7 @@ func Batch[T any](ch <-chan T, size int) (collection []T, length int, readTime t
// BufferWithContext creates a slice of n elements from a channel, with context. Returns the slice and the slice length. // BufferWithContext creates a slice of n elements from a channel, with context. Returns the slice and the slice length.
// @TODO: we should probably provide an helper that reuse the same buffer. // @TODO: we should probably provide an helper that reuse the same buffer.
// Play: https://go.dev/play/p/oRfOyJWK9YF
func BufferWithContext[T any](ctx context.Context, ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) { func BufferWithContext[T any](ctx context.Context, ch <-chan T, size int) (collection []T, length int, readTime time.Duration, ok bool) {
buffer := make([]T, 0, size) buffer := make([]T, 0, size)
now := time.Now() now := time.Now()
@@ -246,6 +258,7 @@ func BufferWithContext[T any](ctx context.Context, ch <-chan T, size int) (colle
} }
// BufferWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length. // BufferWithTimeout creates a slice of n elements from a channel, with timeout. Returns the slice and the slice length.
// Play: https://go.dev/play/p/sxyEM3koo4n
func BufferWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) { func BufferWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (collection []T, length int, readTime time.Duration, ok bool) {
ctx, cancel := context.WithTimeout(context.Background(), timeout) ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel() defer cancel()
@@ -261,6 +274,7 @@ func BatchWithTimeout[T any](ch <-chan T, size int, timeout time.Duration) (coll
// FanIn collects messages from multiple input channels into a single buffered channel. // FanIn collects messages from multiple input channels into a single buffered channel.
// Output messages has no priority. When all upstream channels reach EOF, downstream channel closes. // Output messages has no priority. When all upstream channels reach EOF, downstream channel closes.
// Play: https://go.dev/play/p/FH8Wq-T04Jb
func FanIn[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T { func FanIn[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
out := make(chan T, channelBufferCap) out := make(chan T, channelBufferCap)
var wg sync.WaitGroup var wg sync.WaitGroup
@@ -295,6 +309,7 @@ func ChannelMerge[T any](channelBufferCap int, upstreams ...<-chan T) <-chan T {
// FanOut broadcasts all the upstream messages to multiple downstream channels. // FanOut broadcasts all the upstream messages to multiple downstream channels.
// When upstream channel reach EOF, downstream channels close. If any downstream // When upstream channel reach EOF, downstream channels close. If any downstream
// channels is full, broadcasting is paused. // channels is full, broadcasting is paused.
// Play: https://go.dev/play/p/2LHxcjKX23L
func FanOut[T any](count int, channelsBufferCap int, upstream <-chan T) []<-chan T { func FanOut[T any](count int, channelsBufferCap int, upstream <-chan T) []<-chan T {
downstreams := createChannels[T](count, channelsBufferCap) downstreams := createChannels[T](count, channelsBufferCap)

View File

@@ -17,6 +17,7 @@ func (s *synchronize) Do(cb func()) {
} }
// Synchronize wraps the underlying callback in a mutex. It receives an optional mutex. // Synchronize wraps the underlying callback in a mutex. It receives an optional mutex.
// Play: https://go.dev/play/p/X3cqROSpQmu
func Synchronize(opt ...sync.Locker) *synchronize { //nolint:revive func Synchronize(opt ...sync.Locker) *synchronize { //nolint:revive
if len(opt) > 1 { if len(opt) > 1 {
panic("unexpected arguments") panic("unexpected arguments")
@@ -30,6 +31,7 @@ func Synchronize(opt ...sync.Locker) *synchronize { //nolint:revive
} }
// Async executes a function in a goroutine and returns the result in a channel. // Async executes a function in a goroutine and returns the result in a channel.
// Play: https://go.dev/play/p/uo35gosuTLw
func Async[A any](f func() A) <-chan A { func Async[A any](f func() A) <-chan A {
ch := make(chan A, 1) ch := make(chan A, 1)
go func() { go func() {
@@ -39,6 +41,7 @@ func Async[A any](f func() A) <-chan A {
} }
// Async0 executes a function in a goroutine and returns a channel set once the function finishes. // Async0 executes a function in a goroutine and returns a channel set once the function finishes.
// Play: https://go.dev/play/p/tNqf1cClG_o
func Async0(f func()) <-chan struct{} { func Async0(f func()) <-chan struct{} {
ch := make(chan struct{}, 1) ch := make(chan struct{}, 1)
go func() { go func() {
@@ -49,11 +52,13 @@ func Async0(f func()) <-chan struct{} {
} }
// Async1 is an alias to Async. // Async1 is an alias to Async.
// Play: https://go.dev/play/p/uo35gosuTLw
func Async1[A any](f func() A) <-chan A { func Async1[A any](f func() A) <-chan A {
return Async(f) return Async(f)
} }
// Async2 has the same behavior as Async, but returns the 2 results as a tuple inside the channel. // Async2 has the same behavior as Async, but returns the 2 results as a tuple inside the channel.
// Play: https://go.dev/play/p/7W7mKQi0AhA
func Async2[A, B any](f func() (A, B)) <-chan Tuple2[A, B] { func Async2[A, B any](f func() (A, B)) <-chan Tuple2[A, B] {
ch := make(chan Tuple2[A, B], 1) ch := make(chan Tuple2[A, B], 1)
go func() { go func() {
@@ -63,6 +68,7 @@ func Async2[A, B any](f func() (A, B)) <-chan Tuple2[A, B] {
} }
// Async3 has the same behavior as Async, but returns the 3 results as a tuple inside the channel. // Async3 has the same behavior as Async, but returns the 3 results as a tuple inside the channel.
// Play: https://go.dev/play/p/L1d6o6l6q0d
func Async3[A, B, C any](f func() (A, B, C)) <-chan Tuple3[A, B, C] { func Async3[A, B, C any](f func() (A, B, C)) <-chan Tuple3[A, B, C] {
ch := make(chan Tuple3[A, B, C], 1) ch := make(chan Tuple3[A, B, C], 1)
go func() { go func() {
@@ -72,6 +78,7 @@ func Async3[A, B, C any](f func() (A, B, C)) <-chan Tuple3[A, B, C] {
} }
// Async4 has the same behavior as Async, but returns the 4 results as a tuple inside the channel. // Async4 has the same behavior as Async, but returns the 4 results as a tuple inside the channel.
// Play: https://go.dev/play/p/1X7q6oL0TqF
func Async4[A, B, C, D any](f func() (A, B, C, D)) <-chan Tuple4[A, B, C, D] { func Async4[A, B, C, D any](f func() (A, B, C, D)) <-chan Tuple4[A, B, C, D] {
ch := make(chan Tuple4[A, B, C, D], 1) ch := make(chan Tuple4[A, B, C, D], 1)
go func() { go func() {
@@ -81,6 +88,7 @@ func Async4[A, B, C, D any](f func() (A, B, C, D)) <-chan Tuple4[A, B, C, D] {
} }
// Async5 has the same behavior as Async, but returns the 5 results as a tuple inside the channel. // Async5 has the same behavior as Async, but returns the 5 results as a tuple inside the channel.
// Play: https://go.dev/play/p/2W7q4oL1TqG
func Async5[A, B, C, D, E any](f func() (A, B, C, D, E)) <-chan Tuple5[A, B, C, D, E] { func Async5[A, B, C, D, E any](f func() (A, B, C, D, E)) <-chan Tuple5[A, B, C, D, E] {
ch := make(chan Tuple5[A, B, C, D, E], 1) ch := make(chan Tuple5[A, B, C, D, E], 1)
go func() { go func() {
@@ -90,6 +98,7 @@ func Async5[A, B, C, D, E any](f func() (A, B, C, D, E)) <-chan Tuple5[A, B, C,
} }
// Async6 has the same behavior as Async, but returns the 6 results as a tuple inside the channel. // Async6 has the same behavior as Async, but returns the 6 results as a tuple inside the channel.
// Play: https://go.dev/play/p/3X8q5pM2UrH
func Async6[A, B, C, D, E, F any](f func() (A, B, C, D, E, F)) <-chan Tuple6[A, B, C, D, E, F] { func Async6[A, B, C, D, E, F any](f func() (A, B, C, D, E, F)) <-chan Tuple6[A, B, C, D, E, F] {
ch := make(chan Tuple6[A, B, C, D, E, F], 1) ch := make(chan Tuple6[A, B, C, D, E, F], 1)
go func() { go func() {
@@ -99,6 +108,7 @@ func Async6[A, B, C, D, E, F any](f func() (A, B, C, D, E, F)) <-chan Tuple6[A,
} }
// WaitFor runs periodically until a condition is validated. // WaitFor runs periodically until a condition is validated.
// Play: https://go.dev/play/p/t_wTDmubbK3
func WaitFor(condition func(i int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) { func WaitFor(condition func(i int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
conditionWithContext := func(_ context.Context, currentIteration int) bool { conditionWithContext := func(_ context.Context, currentIteration int) bool {
return condition(currentIteration) return condition(currentIteration)
@@ -107,6 +117,7 @@ func WaitFor(condition func(i int) bool, timeout time.Duration, heartbeatDelay t
} }
// WaitForWithContext runs periodically until a condition is validated or context is canceled. // WaitForWithContext runs periodically until a condition is validated or context is canceled.
// Play: https://go.dev/play/p/t_wTDmubbK3
func WaitForWithContext(ctx context.Context, condition func(ctx context.Context, currentIteration int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) { func WaitForWithContext(ctx context.Context, condition func(ctx context.Context, currentIteration int) bool, timeout time.Duration, heartbeatDelay time.Duration) (totalIterations int, elapsed time.Duration, conditionFound bool) {
start := time.Now() start := time.Now()

View File

@@ -61,7 +61,7 @@ func must(err any, messageArgs ...any) {
// Must is a helper that wraps a call to a function returning a value and an error // Must is a helper that wraps a call to a function returning a value and an error
// and panics if err is error or false. // and panics if err is error or false.
// Play: https://go.dev/play/p/TMoWrRp3DyC // Play: https://go.dev/play/p/fOqtX5HudtN
func Must[T any](val T, err any, messageArgs ...any) T { func Must[T any](val T, err any, messageArgs ...any) T {
must(err, messageArgs...) must(err, messageArgs...)
return val return val

23
find.go
View File

@@ -10,6 +10,7 @@ import (
// IndexOf returns the index at which the first occurrence of a value is found in an array or return -1 // IndexOf 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. // if the value cannot be found.
// Play: https://go.dev/play/p/Eo7W0lvKTky
func IndexOf[T comparable](collection []T, element T) int { func IndexOf[T comparable](collection []T, element T) int {
for i := range collection { for i := range collection {
if collection[i] == element { if collection[i] == element {
@@ -22,6 +23,7 @@ func IndexOf[T comparable](collection []T, element T) int {
// LastIndexOf returns the index at which the last occurrence of a value is found in an array or return -1 // LastIndexOf returns the index at which the last occurrence of a value is found in an array or return -1
// if the value cannot be found. // if the value cannot be found.
// Play: https://go.dev/play/p/Eo7W0lvKTky
func LastIndexOf[T comparable](collection []T, element T) int { func LastIndexOf[T comparable](collection []T, element T) int {
length := len(collection) length := len(collection)
@@ -35,6 +37,7 @@ func LastIndexOf[T comparable](collection []T, element T) int {
} }
// Find search an element in a slice based on a predicate. It returns element and true if element was found. // Find search an element in a slice based on a predicate. It returns element and true if element was found.
// Play: https://go.dev/play/p/Eo7W0lvKTky
func Find[T any](collection []T, predicate func(item T) bool) (T, bool) { func Find[T any](collection []T, predicate func(item T) bool) (T, bool) {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -48,6 +51,7 @@ func Find[T any](collection []T, predicate func(item T) bool) (T, bool) {
// FindIndexOf searches an element in a slice based on a predicate and returns the index and true. // FindIndexOf searches an element in a slice based on a predicate and returns the index and true.
// It returns -1 and false if the element is not found. // It returns -1 and false if the element is not found.
// Play: https://go.dev/play/p/XWSEM4Ic_t0
func FindIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) { func FindIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -61,6 +65,7 @@ func FindIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bo
// FindLastIndexOf searches last element in a slice based on a predicate and returns the index and true. // FindLastIndexOf searches last element in a slice based on a predicate and returns the index and true.
// It returns -1 and false if the element is not found. // It returns -1 and false if the element is not found.
// Play: https://go.dev/play/p/dPiMRtJ6cUx
func FindLastIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) { func FindLastIndexOf[T any](collection []T, predicate func(item T) bool) (T, int, bool) {
length := len(collection) length := len(collection)
@@ -75,6 +80,7 @@ func FindLastIndexOf[T any](collection []T, predicate func(item T) bool) (T, int
} }
// FindOrElse search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise. // FindOrElse search an element in a slice based on a predicate. It returns the element if found or a given fallback value otherwise.
// Play: https://go.dev/play/p/Eo7W0lvKTky
func FindOrElse[T any](collection []T, fallback T, predicate func(item T) bool) T { func FindOrElse[T any](collection []T, fallback T, predicate func(item T) bool) T {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -86,6 +92,7 @@ func FindOrElse[T any](collection []T, fallback T, predicate func(item T) bool)
} }
// FindKey returns the key of the first value matching. // FindKey returns the key of the first value matching.
// Play: https://go.dev/play/p/Bg0w1VDPYXx
func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) { func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) {
for k := range object { for k := range object {
if object[k] == value { if object[k] == value {
@@ -97,6 +104,7 @@ func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) {
} }
// FindKeyBy returns the key of the first element predicate returns truthy for. // FindKeyBy returns the key of the first element predicate returns truthy for.
// Play: https://go.dev/play/p/9IbiPElcyo8
func FindKeyBy[K comparable, V any](object map[K]V, predicate func(key K, value V) bool) (K, bool) { func FindKeyBy[K comparable, V any](object map[K]V, predicate func(key K, value V) bool) (K, bool) {
for k := range object { for k := range object {
if predicate(k, object[k]) { if predicate(k, object[k]) {
@@ -221,6 +229,7 @@ func FindDuplicatesBy[T any, U comparable, Slice ~[]T](collection Slice, iterate
// Min search the minimum value of a collection. // Min search the minimum value of a collection.
// Returns zero value when the collection is empty. // Returns zero value when the collection is empty.
// Play: https://go.dev/play/p/r6e-Z8JozS8
func Min[T constraints.Ordered](collection []T) T { func Min[T constraints.Ordered](collection []T) T {
var min T var min T
@@ -365,6 +374,7 @@ func EarliestBy[T any](collection []T, iteratee func(item T) time.Time) T {
// Max searches the maximum value of a collection. // Max searches the maximum value of a collection.
// Returns zero value when the collection is empty. // Returns zero value when the collection is empty.
// Play: https://go.dev/play/p/r6e-Z8JozS8
func Max[T constraints.Ordered](collection []T) T { func Max[T constraints.Ordered](collection []T) T {
var max T var max T
@@ -508,6 +518,7 @@ func LatestBy[T any](collection []T, iteratee func(item T) time.Time) T {
} }
// First returns the first element of a collection and check for availability of the first element. // First returns the first element of a collection and check for availability of the first element.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func First[T any](collection []T) (T, bool) { func First[T any](collection []T) (T, bool) {
length := len(collection) length := len(collection)
@@ -520,12 +531,14 @@ func First[T any](collection []T) (T, bool) {
} }
// FirstOrEmpty returns the first element of a collection or zero value if empty. // FirstOrEmpty returns the first element of a collection or zero value if empty.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func FirstOrEmpty[T any](collection []T) T { func FirstOrEmpty[T any](collection []T) T {
i, _ := First(collection) i, _ := First(collection)
return i return i
} }
// FirstOr returns the first element of a collection or the fallback value if empty. // FirstOr returns the first element of a collection or the fallback value if empty.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func FirstOr[T any](collection []T, fallback T) T { func FirstOr[T any](collection []T, fallback T) T {
i, ok := First(collection) i, ok := First(collection)
if !ok { if !ok {
@@ -536,6 +549,7 @@ func FirstOr[T any](collection []T, fallback T) T {
} }
// Last returns the last element of a collection or error if empty. // Last returns the last element of a collection or error if empty.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func Last[T any](collection []T) (T, bool) { func Last[T any](collection []T) (T, bool) {
length := len(collection) length := len(collection)
@@ -548,12 +562,14 @@ func Last[T any](collection []T) (T, bool) {
} }
// LastOrEmpty returns the last element of a collection or zero value if empty. // LastOrEmpty returns the last element of a collection or zero value if empty.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func LastOrEmpty[T any](collection []T) T { func LastOrEmpty[T any](collection []T) T {
i, _ := Last(collection) i, _ := Last(collection)
return i return i
} }
// LastOr returns the last element of a collection or the fallback value if empty. // LastOr returns the last element of a collection or the fallback value if empty.
// Play: https://go.dev/play/p/ul45Z0y2EFO
func LastOr[T any](collection []T, fallback T) T { func LastOr[T any](collection []T, fallback T) T {
i, ok := Last(collection) i, ok := Last(collection)
if !ok { if !ok {
@@ -565,6 +581,7 @@ func LastOr[T any](collection []T, fallback T) T {
// Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element // Nth returns the element at index `nth` of collection. If `nth` is negative, the nth element
// from the end is returned. An error is returned when nth is out of slice bounds. // from the end is returned. An error is returned when nth is out of slice bounds.
// Play: https://go.dev/play/p/sHoh88KWt6B
func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) { func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) {
n := int(nth) n := int(nth)
l := len(collection) l := len(collection)
@@ -582,6 +599,7 @@ func Nth[T any, N constraints.Integer](collection []T, nth N) (T, error) {
// NthOr returns the element at index `nth` of collection. // NthOr returns the element at index `nth` of collection.
// If `nth` is negative, it returns the nth element from the end. // If `nth` is negative, it returns the nth element from the end.
// If `nth` is out of slice bounds, it returns the fallback value instead of an error. // If `nth` is out of slice bounds, it returns the fallback value instead of an error.
// Play: https://go.dev/play/p/sHoh88KWt6B
func NthOr[T any, N constraints.Integer](collection []T, nth N, fallback T) T { func NthOr[T any, N constraints.Integer](collection []T, nth N, fallback T) T {
value, err := Nth(collection, nth) value, err := Nth(collection, nth)
if err != nil { if err != nil {
@@ -593,6 +611,7 @@ func NthOr[T any, N constraints.Integer](collection []T, nth N, fallback T) T {
// NthOrEmpty returns the element at index `nth` of collection. // NthOrEmpty returns the element at index `nth` of collection.
// If `nth` is negative, it returns the nth element from the end. // If `nth` is negative, it returns the nth element from the end.
// If `nth` is out of slice bounds, it returns the zero value (empty value) for that type. // If `nth` is out of slice bounds, it returns the zero value (empty value) for that type.
// Play: https://go.dev/play/p/sHoh88KWt6B
func NthOrEmpty[T any, N constraints.Integer](collection []T, nth N) T { func NthOrEmpty[T any, N constraints.Integer](collection []T, nth N) T {
value, err := Nth(collection, nth) value, err := Nth(collection, nth)
if err != nil { if err != nil {
@@ -607,12 +626,14 @@ func NthOrEmpty[T any, N constraints.Integer](collection []T, nth N) T {
type randomIntGenerator func(n int) int type randomIntGenerator func(n int) int
// Sample returns a random item from collection. // Sample returns a random item from collection.
// Play: https://go.dev/play/p/vCcSJbh5s6l
func Sample[T any](collection []T) T { func Sample[T any](collection []T) T {
result := SampleBy(collection, rand.IntN) result := SampleBy(collection, rand.IntN)
return result return result
} }
// SampleBy returns a random item from collection, using randomIntGenerator as the random index generator. // SampleBy returns a random item from collection, using randomIntGenerator as the random index generator.
// Play: https://go.dev/play/p/HDmKmMgq0XN
func SampleBy[T any](collection []T, randomIntGenerator randomIntGenerator) T { func SampleBy[T any](collection []T, randomIntGenerator randomIntGenerator) T {
size := len(collection) size := len(collection)
if size == 0 { if size == 0 {
@@ -622,12 +643,14 @@ func SampleBy[T any](collection []T, randomIntGenerator randomIntGenerator) T {
} }
// Samples returns N random unique items from collection. // Samples returns N random unique items from collection.
// Play: https://go.dev/play/p/vCcSJbh5s6l
func Samples[T any, Slice ~[]T](collection Slice, count int) Slice { func Samples[T any, Slice ~[]T](collection Slice, count int) Slice {
results := SamplesBy(collection, count, rand.IntN) results := SamplesBy(collection, count, rand.IntN)
return results return results
} }
// SamplesBy returns N random unique items from collection, using randomIntGenerator as the random index generator. // SamplesBy returns N random unique items from collection, using randomIntGenerator as the random index generator.
// Play: https://go.dev/play/p/HDmKmMgq0XN
func SamplesBy[T any, Slice ~[]T](collection Slice, count int, randomIntGenerator randomIntGenerator) Slice { func SamplesBy[T any, Slice ~[]T](collection Slice, count int, randomIntGenerator randomIntGenerator) Slice {
size := len(collection) size := len(collection)

View File

@@ -1,6 +1,7 @@
package lo package lo
// Partial returns new function that, when called, has its first argument set to the provided value. // Partial returns new function that, when called, has its first argument set to the provided value.
// Play: https://go.dev/play/p/Sy1gAQiQZ3v
func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R { func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R {
return func(t2 T2) R { return func(t2 T2) R {
return f(arg1, t2) return f(arg1, t2)
@@ -8,11 +9,13 @@ func Partial[T1, T2, R any](f func(a T1, b T2) R, arg1 T1) func(T2) R {
} }
// Partial1 returns new function that, when called, has its first argument set to the provided value. // Partial1 returns new function that, when called, has its first argument set to the provided value.
// Play: https://go.dev/play/p/D-ASTXCLBzw
func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R { func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R {
return Partial(f, arg1) return Partial(f, arg1)
} }
// Partial2 returns new function that, when called, has its first argument set to the provided value. // Partial2 returns new function that, when called, has its first argument set to the provided value.
// Play: https://go.dev/play/p/-xiPjy4JChJ
func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R { func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R {
return func(t2 T2, t3 T3) R { return func(t2 T2, t3 T3) R {
return f(arg1, t2, t3) return f(arg1, t2, t3)
@@ -20,6 +23,7 @@ func Partial2[T1, T2, T3, R any](f func(T1, T2, T3) R, arg1 T1) func(T2, T3) R {
} }
// Partial3 returns new function that, when called, has its first argument set to the provided value. // Partial3 returns new function that, when called, has its first argument set to the provided value.
// Play: https://go.dev/play/p/zWtSutpI26m
func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2, T3, T4) R { func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2, T3, T4) R {
return func(t2 T2, t3 T3, t4 T4) R { return func(t2 T2, t3 T3, t4 T4) R {
return f(arg1, t2, t3, t4) return f(arg1, t2, t3, t4)
@@ -27,6 +31,7 @@ func Partial3[T1, T2, T3, T4, R any](f func(T1, T2, T3, T4) R, arg1 T1) func(T2,
} }
// Partial4 returns new function that, when called, has its first argument set to the provided value. // Partial4 returns new function that, when called, has its first argument set to the provided value.
// Play: https://go.dev/play/p/kBrnnMTcJm0
func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1) func(T2, T3, T4, T5) R { func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1) func(T2, T3, T4, T5) R {
return func(t2 T2, t3 T3, t4 T4, t5 T5) R { return func(t2 T2, t3 T3, t4 T4, t5 T5) R {
return f(arg1, t2, t3, t4, t5) return f(arg1, t2, t3, t4, t5)
@@ -34,6 +39,7 @@ func Partial4[T1, T2, T3, T4, T5, R any](f func(T1, T2, T3, T4, T5) R, arg1 T1)
} }
// Partial5 returns new function that, when called, has its first argument set to the provided value // Partial5 returns new function that, when called, has its first argument set to the provided value
// Play: https://go.dev/play/p/7Is7K2y_VC3
func Partial5[T1, T2, T3, T4, T5, T6, R any](f func(T1, T2, T3, T4, T5, T6) R, arg1 T1) func(T2, T3, T4, T5, T6) R { func Partial5[T1, T2, T3, T4, T5, T6, R any](f func(T1, T2, T3, T4, T5, T6) R, arg1 T1) func(T2, T3, T4, T5, T6) R {
return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R { return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R {
return f(arg1, t2, t3, t4, t5, t6) return f(arg1, t2, t3, t4, t5, t6)

View File

@@ -1,6 +1,7 @@
package lo package lo
// Contains returns true if an element is present in a collection. // Contains returns true if an element is present in a collection.
// Play: https://go.dev/play/p/W1EvyqY6t9j
func Contains[T comparable](collection []T, element T) bool { func Contains[T comparable](collection []T, element T) bool {
for i := range collection { for i := range collection {
if collection[i] == element { if collection[i] == element {
@@ -12,6 +13,7 @@ func Contains[T comparable](collection []T, element T) bool {
} }
// ContainsBy returns true if predicate function return true. // ContainsBy returns true if predicate function return true.
// Play: https://go.dev/play/p/W1EvyqY6t9j
func ContainsBy[T any](collection []T, predicate func(item T) bool) bool { func ContainsBy[T any](collection []T, predicate func(item T) bool) bool {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -23,6 +25,7 @@ func ContainsBy[T any](collection []T, predicate func(item T) bool) bool {
} }
// Every returns true if all elements of a subset are contained into a collection or if the subset is empty. // Every returns true if all elements of a subset are contained into a collection or if the subset is empty.
// Play: https://go.dev/play/p/W1EvyqY6t9j
func Every[T comparable](collection []T, subset []T) bool { func Every[T comparable](collection []T, subset []T) bool {
for i := range subset { for i := range subset {
if !Contains(collection, subset[i]) { if !Contains(collection, subset[i]) {
@@ -34,6 +37,7 @@ func Every[T comparable](collection []T, subset []T) bool {
} }
// EveryBy returns true if the predicate returns true for all elements in the collection or if the collection is empty. // EveryBy returns true if the predicate returns true for all elements in the collection or if the collection is empty.
// Play: https://go.dev/play/p/dn1-vhHsq9x
func EveryBy[T any](collection []T, predicate func(item T) bool) bool { func EveryBy[T any](collection []T, predicate func(item T) bool) bool {
for i := range collection { for i := range collection {
if !predicate(collection[i]) { if !predicate(collection[i]) {
@@ -46,6 +50,7 @@ func EveryBy[T any](collection []T, predicate func(item T) bool) bool {
// Some returns true if at least 1 element of a subset is contained into a collection. // Some returns true if at least 1 element of a subset is contained into a collection.
// If the subset is empty Some returns false. // If the subset is empty Some returns false.
// Play: https://go.dev/play/p/Lj4ceFkeT9V
func Some[T comparable](collection []T, subset []T) bool { func Some[T comparable](collection []T, subset []T) bool {
for i := range subset { for i := range subset {
if Contains(collection, subset[i]) { if Contains(collection, subset[i]) {
@@ -58,6 +63,7 @@ func Some[T comparable](collection []T, subset []T) bool {
// SomeBy returns true if the predicate returns true for any of the elements in the collection. // SomeBy returns true if the predicate returns true for any of the elements in the collection.
// If the collection is empty SomeBy returns false. // If the collection is empty SomeBy returns false.
// Play: https://go.dev/play/p/DXF-TORBudx
func SomeBy[T any](collection []T, predicate func(item T) bool) bool { func SomeBy[T any](collection []T, predicate func(item T) bool) bool {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -69,6 +75,7 @@ func SomeBy[T any](collection []T, predicate func(item T) bool) bool {
} }
// None returns true if no element of a subset are contained into a collection or if the subset is empty. // None returns true if no element of a subset are contained into a collection or if the subset is empty.
// Play: https://go.dev/play/p/fye7JsmxzPV
func None[T comparable](collection []T, subset []T) bool { func None[T comparable](collection []T, subset []T) bool {
for i := range subset { for i := range subset {
if Contains(collection, subset[i]) { if Contains(collection, subset[i]) {
@@ -80,6 +87,7 @@ func None[T comparable](collection []T, subset []T) bool {
} }
// NoneBy returns true if the predicate returns true for none of the elements in the collection or if the collection is empty. // NoneBy returns true if the predicate returns true for none of the elements in the collection or if the collection is empty.
// Play: https://go.dev/play/p/O64WZ32H58S
func NoneBy[T any](collection []T, predicate func(item T) bool) bool { func NoneBy[T any](collection []T, predicate func(item T) bool) bool {
for i := range collection { for i := range collection {
if predicate(collection[i]) { if predicate(collection[i]) {
@@ -91,6 +99,7 @@ func NoneBy[T any](collection []T, predicate func(item T) bool) bool {
} }
// Intersect returns the intersection between two collections. // Intersect returns the intersection between two collections.
// Play: https://go.dev/play/p/uuElL9X9e58
func Intersect[T comparable, Slice ~[]T](list1 Slice, list2 Slice) Slice { func Intersect[T comparable, Slice ~[]T](list1 Slice, list2 Slice) Slice {
result := Slice{} result := Slice{}
seen := map[T]struct{}{} seen := map[T]struct{}{}
@@ -111,6 +120,7 @@ func Intersect[T comparable, Slice ~[]T](list1 Slice, list2 Slice) Slice {
// Difference returns the difference between two collections. // Difference returns the difference between two collections.
// The first value is the collection of element absent of list2. // The first value is the collection of element absent of list2.
// The second value is the collection of element absent of list1. // The second value is the collection of element absent of list1.
// Play: https://go.dev/play/p/pKE-JgzqRpz
func Difference[T comparable, Slice ~[]T](list1 Slice, list2 Slice) (Slice, Slice) { func Difference[T comparable, Slice ~[]T](list1 Slice, list2 Slice) (Slice, Slice) {
left := Slice{} left := Slice{}
right := Slice{} right := Slice{}
@@ -143,6 +153,7 @@ func Difference[T comparable, Slice ~[]T](list1 Slice, list2 Slice) (Slice, Slic
// Union returns all distinct elements from given collections. // Union returns all distinct elements from given collections.
// result returns will not change the order of elements relatively. // result returns will not change the order of elements relatively.
// Play: https://go.dev/play/p/DI9RVEB_qMK
func Union[T comparable, Slice ~[]T](lists ...Slice) Slice { func Union[T comparable, Slice ~[]T](lists ...Slice) Slice {
var capLen int var capLen int
@@ -166,6 +177,7 @@ func Union[T comparable, Slice ~[]T](lists ...Slice) Slice {
} }
// Without returns slice excluding all given values. // Without returns slice excluding all given values.
// Play: https://go.dev/play/p/5j30Ux8TaD0
func Without[T comparable, Slice ~[]T](collection Slice, exclude ...T) Slice { func Without[T comparable, Slice ~[]T](collection Slice, exclude ...T) Slice {
excludeMap := make(map[T]struct{}, len(exclude)) excludeMap := make(map[T]struct{}, len(exclude))
for i := range exclude { for i := range exclude {
@@ -183,6 +195,7 @@ func Without[T comparable, Slice ~[]T](collection Slice, exclude ...T) Slice {
// WithoutBy filters a slice by excluding elements whose extracted keys match any in the exclude list. // WithoutBy filters a slice by excluding elements whose extracted keys match any in the exclude list.
// It returns a new slice containing only the elements whose keys are not in the exclude list. // It returns a new slice containing only the elements whose keys are not in the exclude list.
// Play: https://go.dev/play/p/VgWJOF01NbJ
func WithoutBy[T any, K comparable](collection []T, iteratee func(item T) K, exclude ...K) []T { func WithoutBy[T any, K comparable](collection []T, iteratee func(item T) K, exclude ...K) []T {
excludeMap := make(map[K]struct{}, len(exclude)) excludeMap := make(map[K]struct{}, len(exclude))
for _, e := range exclude { for _, e := range exclude {
@@ -206,6 +219,7 @@ func WithoutEmpty[T comparable, Slice ~[]T](collection Slice) Slice {
} }
// WithoutNth returns slice excluding nth value. // WithoutNth returns slice excluding nth value.
// Play: https://go.dev/play/p/5g3F9R2H1xL
func WithoutNth[T comparable, Slice ~[]T](collection Slice, nths ...int) Slice { func WithoutNth[T comparable, Slice ~[]T](collection Slice, nths ...int) Slice {
length := len(collection) length := len(collection)
@@ -229,6 +243,7 @@ func WithoutNth[T comparable, Slice ~[]T](collection Slice, nths ...int) Slice {
// ElementsMatch returns true if lists contain the same set of elements (including empty set). // ElementsMatch returns true if lists contain the same set of elements (including empty set).
// If there are duplicate elements, the number of appearances of each of them in both lists should match. // If there are duplicate elements, the number of appearances of each of them in both lists should match.
// The order of elements is not checked. // The order of elements is not checked.
// Play: https://go.dev/play/p/XWSEM4Ic_t0
func ElementsMatch[T comparable, Slice ~[]T](list1 Slice, list2 Slice) bool { func ElementsMatch[T comparable, Slice ~[]T](list1 Slice, list2 Slice) bool {
return ElementsMatchBy(list1, list2, func(item T) T { return item }) return ElementsMatchBy(list1, list2, func(item T) T { return item })
} }
@@ -236,6 +251,7 @@ func ElementsMatch[T comparable, Slice ~[]T](list1 Slice, list2 Slice) bool {
// ElementsMatchBy returns true if lists contain the same set of elements' keys (including empty set). // ElementsMatchBy returns true if lists contain the same set of elements' keys (including empty set).
// If there are duplicate keys, the number of appearances of each of them in both lists should match. // If there are duplicate keys, the number of appearances of each of them in both lists should match.
// The order of elements is not checked. // The order of elements is not checked.
// Play: https://go.dev/play/p/XWSEM4Ic_t0
func ElementsMatchBy[T any, K comparable](list1 []T, list2 []T, iteratee func(item T) K) bool { func ElementsMatchBy[T any, K comparable](list1 []T, list2 []T, iteratee func(item T) K) bool {
if len(list1) != len(list2) { if len(list1) != len(list2) {
return false return false

3
map.go
View File

@@ -175,7 +175,7 @@ func OmitByValues[K comparable, V comparable, Map ~map[K]V](in Map, values []V)
} }
// Entries transforms a map into array of key/value pairs. // Entries transforms a map into array of key/value pairs.
// Play: // Play: https://go.dev/play/p/_t4Xe34-Nl5
func Entries[K comparable, V any](in map[K]V) []Entry[K, V] { func Entries[K comparable, V any](in map[K]V) []Entry[K, V] {
entries := make([]Entry[K, V], 0, len(in)) entries := make([]Entry[K, V], 0, len(in))
@@ -331,6 +331,7 @@ func MapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(key K, val
// The iteratee returns a value and a boolean. If the boolean is true, the value is added to the result slice. // The iteratee returns a value and a boolean. If the boolean is true, the value is added to the result slice.
// If the boolean is false, the value is not added to the result slice. // If the boolean is false, the value is not added to the result slice.
// The order of the keys in the input map is not specified and the order of the keys in the output slice is not guaranteed. // The order of the keys in the input map is not specified and the order of the keys in the output slice is not guaranteed.
// Play: https://go.dev/play/p/jgsD_Kil9pV
func FilterMapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(key K, value V) (R, bool)) []R { func FilterMapToSlice[K comparable, V any, R any](in map[K]V, iteratee func(key K, value V) (R, bool)) []R {
result := make([]R, 0, len(in)) result := make([]R, 0, len(in))

View File

@@ -122,6 +122,7 @@ func ProductBy[T any, R constraints.Float | constraints.Integer | constraints.Co
} }
// Mean calculates the mean of a collection of numbers. // Mean calculates the mean of a collection of numbers.
// Play: https://go.dev/play/p/tPURSuteUsP
func Mean[T constraints.Float | constraints.Integer](collection []T) T { func Mean[T constraints.Float | constraints.Integer](collection []T) T {
length := T(len(collection)) length := T(len(collection))
if length == 0 { if length == 0 {
@@ -132,6 +133,7 @@ func Mean[T constraints.Float | constraints.Integer](collection []T) T {
} }
// MeanBy calculates the mean of a collection of numbers using the given return value from the iteration function. // MeanBy calculates the mean of a collection of numbers using the given return value from the iteration function.
// Play: https://go.dev/play/p/j7TsVwBOZ7P
func MeanBy[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) R) R { func MeanBy[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) R) R {
length := R(len(collection)) length := R(len(collection))
if length == 0 { if length == 0 {

View File

@@ -7,6 +7,7 @@ import "github.com/samber/lo/internal/rand"
// and should return true for elements that should be kept and false for elements that should be removed. // and should return true for elements that should be kept and false for elements that should be removed.
// The function returns the modified slice, which may be shorter than the original if some elements were removed. // The function returns the modified slice, which may be shorter than the original if some elements were removed.
// Note that the order of elements in the original slice is preserved in the output. // Note that the order of elements in the original slice is preserved in the output.
// Play: https://go.dev/play/p/0jY3Z0B7O_5
func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice { func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice {
j := 0 j := 0
for _, item := range collection { for _, item := range collection {
@@ -36,6 +37,7 @@ func FilterI[T any, Slice ~[]T](collection Slice, predicate func(item T, index i
// Map is a generic function that modifies the input slice in-place to contain the result of applying the provided // Map is a generic function that modifies the input slice in-place to contain the result of applying the provided
// function to each element of the slice. The function returns the modified slice, which has the same length as the original. // function to each element of the slice. The function returns the modified slice, which has the same length as the original.
// Play: https://go.dev/play/p/0jY3Z0B7O_5
func Map[T any, Slice ~[]T](collection Slice, fn func(item T) T) { func Map[T any, Slice ~[]T](collection Slice, fn func(item T) T) {
for i := range collection { for i := range collection {
collection[i] = fn(collection[i]) collection[i] = fn(collection[i])

View File

@@ -4,6 +4,7 @@ import "sync"
// Map manipulates a slice and transforms it to a slice of another type. // Map manipulates a slice and transforms it to a slice of another type.
// `iteratee` is call in parallel. Result keep the same order. // `iteratee` is call in parallel. Result keep the same order.
// Play: https://go.dev/play/p/sCJaB3quRMC
func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R { func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R {
result := make([]R, len(collection)) result := make([]R, len(collection))
@@ -27,6 +28,7 @@ func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R {
// ForEach iterates over elements of collection and invokes iteratee for each element. // ForEach iterates over elements of collection and invokes iteratee for each element.
// `iteratee` is call in parallel. // `iteratee` is call in parallel.
// Play: https://go.dev/play/p/sCJaB3quRMC
func ForEach[T any](collection []T, iteratee func(item T, index int)) { func ForEach[T any](collection []T, iteratee func(item T, index int)) {
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(len(collection)) wg.Add(len(collection))

View File

@@ -194,6 +194,7 @@ func AttemptWithDelay(maxIteration int, delay time.Duration, f func(index int, d
// immediately if the second return value is false. When the first // immediately if the second return value is false. When the first
// argument is less than `1`, the function runs until a successful response is // argument is less than `1`, the function runs until a successful response is
// returned. // returned.
// Play: https://go.dev/play/p/1VS7HxlYMOG
func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) { func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) {
var err error var err error
var shouldContinueInvoke bool var shouldContinueInvoke bool
@@ -218,6 +219,7 @@ func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) {
// It will terminate the invoke immediately if the second return value is false. // It will terminate the invoke immediately if the second return value is false.
// When the first argument is less than `1`, the function runs until a successful // When the first argument is less than `1`, the function runs until a successful
// response is returned. // response is returned.
// Play: https://go.dev/play/p/mhufUjJfLEF
func AttemptWhileWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) (error, bool)) (int, time.Duration, error) { func AttemptWhileWithDelay(maxIteration int, delay time.Duration, f func(int, time.Duration) (error, bool)) (int, time.Duration, error) {
var err error var err error
var shouldContinueInvoke bool var shouldContinueInvoke bool
@@ -247,6 +249,7 @@ type transactionStep[T any] struct {
} }
// NewTransaction instantiate a new transaction. // NewTransaction instantiate a new transaction.
// Play: https://go.dev/play/p/Qxrd7MGQGh1
func NewTransaction[T any]() *Transaction[T] { func NewTransaction[T any]() *Transaction[T] {
return &Transaction[T]{ return &Transaction[T]{
steps: []transactionStep[T]{}, steps: []transactionStep[T]{},
@@ -259,6 +262,7 @@ type Transaction[T any] struct {
} }
// Then adds a step to the chain of callbacks. It returns the same Transaction. // Then adds a step to the chain of callbacks. It returns the same Transaction.
// Play: https://go.dev/play/p/Qxrd7MGQGh1 https://go.dev/play/p/xrHb2_kMvTY
func (t *Transaction[T]) Then(exec func(T) (T, error), onRollback func(T) T) *Transaction[T] { func (t *Transaction[T]) Then(exec func(T) (T, error), onRollback func(T) T) *Transaction[T] {
t.steps = append(t.steps, transactionStep[T]{ t.steps = append(t.steps, transactionStep[T]{
exec: exec, exec: exec,
@@ -269,6 +273,7 @@ func (t *Transaction[T]) Then(exec func(T) (T, error), onRollback func(T) T) *Tr
} }
// Process runs the Transaction steps and rollbacks in case of errors. // Process runs the Transaction steps and rollbacks in case of errors.
// Play: https://go.dev/play/p/Qxrd7MGQGh1 https://go.dev/play/p/xrHb2_kMvTY
func (t *Transaction[T]) Process(state T) (T, error) { func (t *Transaction[T]) Process(state T) (T, error) {
var i int var i int
var err error var err error
@@ -341,11 +346,13 @@ func (th *throttleBy[T]) reset() {
// NewThrottle creates a throttled instance that invokes given functions only once in every interval. // NewThrottle creates a throttled instance that invokes given functions only once in every interval.
// This returns 2 functions, First one is throttled function and Second one is a function to reset interval // This returns 2 functions, First one is throttled function and Second one is a function to reset interval
// Play: https://go.dev/play/p/qQn3fm8Z7jS
func NewThrottle(interval time.Duration, f ...func()) (throttle func(), reset func()) { func NewThrottle(interval time.Duration, f ...func()) (throttle func(), reset func()) {
return NewThrottleWithCount(interval, 1, f...) return NewThrottleWithCount(interval, 1, f...)
} }
// NewThrottleWithCount is NewThrottle with count limit, throttled function will be invoked count times in every interval. // NewThrottleWithCount is NewThrottle with count limit, throttled function will be invoked count times in every interval.
// Play: https://go.dev/play/p/w5nc0MgWtjC
func NewThrottleWithCount(interval time.Duration, count int, f ...func()) (throttle func(), reset func()) { func NewThrottleWithCount(interval time.Duration, count int, f ...func()) (throttle func(), reset func()) {
callbacks := Map(f, func(item func(), _ int) func(struct{}) { callbacks := Map(f, func(item func(), _ int) func(struct{}) {
return func(struct{}) { return func(struct{}) {
@@ -361,11 +368,13 @@ func NewThrottleWithCount(interval time.Duration, count int, f ...func()) (throt
// NewThrottleBy creates a throttled instance that invokes given functions only once in every interval. // NewThrottleBy creates a throttled instance that invokes given functions only once in every interval.
// This returns 2 functions, First one is throttled function and Second one is a function to reset interval // This returns 2 functions, First one is throttled function and Second one is a function to reset interval
// Play: https://go.dev/play/p/0Wv6oX7dHdC
func NewThrottleBy[T comparable](interval time.Duration, f ...func(key T)) (throttle func(key T), reset func()) { func NewThrottleBy[T comparable](interval time.Duration, f ...func(key T)) (throttle func(key T), reset func()) {
return NewThrottleByWithCount[T](interval, 1, f...) return NewThrottleByWithCount[T](interval, 1, f...)
} }
// NewThrottleByWithCount is NewThrottleBy with count limit, throttled function will be invoked count times in every interval. // NewThrottleByWithCount is NewThrottleBy with count limit, throttled function will be invoked count times in every interval.
// Play: https://go.dev/play/p/vQk3ECH7_EW
func NewThrottleByWithCount[T comparable](interval time.Duration, count int, f ...func(key T)) (throttle func(key T), reset func()) { func NewThrottleByWithCount[T comparable](interval time.Duration, count int, f ...func(key T)) (throttle func(key T), reset func()) {
if count <= 0 { if count <= 0 {
count = 1 count = 1

View File

@@ -34,6 +34,7 @@ func Map[T any, R any](collection []T, iteratee func(item T, index int) R) []R {
} }
// UniqMap manipulates a slice and transforms it to a slice of another type with unique values. // UniqMap manipulates a slice and transforms it to a slice of another type with unique values.
// Play: https://go.dev/play/p/fygzLBhvUdB
func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index int) R) []R { func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index int) R) []R {
result := make([]R, 0, len(collection)) result := make([]R, 0, len(collection))
seen := make(map[R]struct{}, len(collection)) seen := make(map[R]struct{}, len(collection))
@@ -53,7 +54,7 @@ func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index in
// - the result of the mapping operation and // - the result of the mapping operation and
// - whether the result element should be included or not. // - whether the result element should be included or not.
// //
// Play: https://go.dev/play/p/-AuYXfy7opz // Play: https://go.dev/play/p/CgHYNUpOd1I
func FilterMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R { func FilterMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R {
result := make([]R, 0, len(collection)) result := make([]R, 0, len(collection))
@@ -69,7 +70,7 @@ func FilterMap[T any, R any](collection []T, callback func(item T, index int) (R
// FlatMap manipulates a slice and transforms and flattens it to a slice of another type. // FlatMap manipulates a slice and transforms and flattens it to a slice of another type.
// The transform function can either return a slice or a `nil`, and in the `nil` case // The transform function can either return a slice or a `nil`, and in the `nil` case
// no value is added to the final slice. // no value is added to the final slice.
// Play: https://go.dev/play/p/YSoYmQTA8-U // Play: https://go.dev/play/p/pFCF5WVB225
func FlatMap[T any, R any](collection []T, iteratee func(item T, index int) []R) []R { func FlatMap[T any, R any](collection []T, iteratee func(item T, index int) []R) []R {
result := make([]R, 0, len(collection)) result := make([]R, 0, len(collection))
@@ -82,7 +83,7 @@ func FlatMap[T any, R any](collection []T, iteratee func(item T, index int) []R)
// Reduce reduces collection to a value which is the accumulated result of running each element in collection // Reduce reduces collection to a value which is the accumulated result of running each element in collection
// through accumulator, where each successive invocation is supplied the return value of the previous. // through accumulator, where each successive invocation is supplied the return value of the previous.
// Play: https://go.dev/play/p/R4UHXZNaaUG // Play: https://go.dev/play/p/CgHYNUpOd1I
func Reduce[T any, R any](collection []T, accumulator func(agg R, item T, index int) R, initial R) R { func Reduce[T any, R any](collection []T, accumulator func(agg R, item T, index int) R, initial R) R {
for i := range collection { for i := range collection {
initial = accumulator(initial, collection[i], i) initial = accumulator(initial, collection[i], i)
@@ -189,6 +190,7 @@ func GroupBy[T any, U comparable, Slice ~[]T](collection Slice, iteratee func(it
} }
// GroupByMap returns an object composed of keys generated from the results of running each element of collection through iteratee. // GroupByMap returns an object composed of keys generated from the results of running each element of collection through iteratee.
// Play: https://go.dev/play/p/iMeruQ3_W80
func GroupByMap[T any, K comparable, V any](collection []T, iteratee func(item T) (K, V)) map[K][]V { func GroupByMap[T any, K comparable, V any](collection []T, iteratee func(item T) (K, V)) map[K][]V {
result := map[K][]V{} result := map[K][]V{}
@@ -203,7 +205,7 @@ func GroupByMap[T any, K comparable, V any](collection []T, iteratee func(item T
// Chunk returns an array of elements split into groups the length of size. If array can't be split evenly, // Chunk returns an array of elements split into groups the length of size. If array can't be split evenly,
// the final chunk will be the remaining elements. // the final chunk will be the remaining elements.
// Play: https://go.dev/play/p/EeKl0AuTehH // Play: https://go.dev/play/p/kEMkFbdu85g
func Chunk[T any, Slice ~[]T](collection Slice, size int) []Slice { func Chunk[T any, Slice ~[]T](collection Slice, size int) []Slice {
if size <= 0 { if size <= 0 {
panic("Second parameter must be greater than 0") panic("Second parameter must be greater than 0")
@@ -368,7 +370,7 @@ func RepeatBy[T any](count int, predicate func(index int) T) []T {
} }
// KeyBy transforms a slice or an array of structs to a map based on a pivot callback. // KeyBy transforms a slice or an array of structs to a map based on a pivot callback.
// Play: https://go.dev/play/p/mdaClUAT-zZ // Play: https://go.dev/play/p/ccUiUL_Lnel
func KeyBy[K comparable, V any](collection []V, iteratee func(item V) K) map[K]V { func KeyBy[K comparable, V any](collection []V, iteratee func(item V) K) map[K]V {
result := make(map[K]V, len(collection)) result := make(map[K]V, len(collection))
@@ -408,6 +410,7 @@ func SliceToMap[T any, K comparable, V any](collection []T, transform func(item
// If any of two pairs would have the same key the last one gets added to the map. // If any of two pairs would have the same key the last one gets added to the map.
// The order of keys in returned map is not specified and is not guaranteed to be the same from the original array. // The order of keys in returned map is not specified and is not guaranteed to be the same from the original array.
// The third return value of the transform function is a boolean that indicates whether the key-value pair should be included in the map. // The third return value of the transform function is a boolean that indicates whether the key-value pair should be included in the map.
// Play: https://go.dev/play/p/2z0rDz2ZSGU
func FilterSliceToMap[T any, K comparable, V any](collection []T, transform func(item T) (K, V, bool)) map[K]V { func FilterSliceToMap[T any, K comparable, V any](collection []T, transform func(item T) (K, V, bool)) map[K]V {
result := make(map[K]V, len(collection)) result := make(map[K]V, len(collection))
@@ -422,6 +425,7 @@ func FilterSliceToMap[T any, K comparable, V any](collection []T, transform func
} }
// Keyify returns a map with each unique element of the slice as a key. // Keyify returns a map with each unique element of the slice as a key.
// Play: https://go.dev/play/p/RYhhM_csqIG
func Keyify[T comparable, Slice ~[]T](collection Slice) map[T]struct{} { func Keyify[T comparable, Slice ~[]T](collection Slice) map[T]struct{} {
result := make(map[T]struct{}, len(collection)) result := make(map[T]struct{}, len(collection))
@@ -516,7 +520,7 @@ func DropByIndex[T any](collection []T, indexes ...int) []T {
} }
// Reject is the opposite of Filter, this method returns the elements of collection that predicate does not return truthy for. // Reject is the opposite of Filter, this method returns the elements of collection that predicate does not return truthy for.
// Play: https://go.dev/play/p/YkLMODy1WEL // Play: https://go.dev/play/p/pFCF5WVB225
func Reject[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice { func Reject[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice {
result := Slice{} result := Slice{}
@@ -533,6 +537,8 @@ func Reject[T any, Slice ~[]T](collection Slice, predicate func(item T, index in
// The callback function should return two values: // The callback function should return two values:
// - the result of the mapping operation and // - the result of the mapping operation and
// - whether the result element should be included or not. // - whether the result element should be included or not.
//
// Play: https://go.dev/play/p/W9Ug9r0QFkL
func RejectMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R { func RejectMap[T any, R any](collection []T, callback func(item T, index int) (R, bool)) []R {
result := []R{} result := []R{}
@@ -547,6 +553,7 @@ func RejectMap[T any, R any](collection []T, callback func(item T, index int) (R
// FilterReject mixes Filter and Reject, this method returns two slices, one for the elements of collection that // FilterReject mixes Filter and Reject, this method returns two slices, one for the elements of collection that
// predicate returns truthy for and one for the elements that predicate does not return truthy for. // predicate returns truthy for and one for the elements that predicate does not return truthy for.
// Play: https://go.dev/play/p/lHSEGSznJjB
func FilterReject[T any, Slice ~[]T](collection Slice, predicate func(T, int) bool) (kept Slice, rejected Slice) { func FilterReject[T any, Slice ~[]T](collection Slice, predicate func(T, int) bool) (kept Slice, rejected Slice) {
kept = make(Slice, 0, len(collection)) kept = make(Slice, 0, len(collection))
rejected = make(Slice, 0, len(collection)) rejected = make(Slice, 0, len(collection))

View File

@@ -151,6 +151,7 @@ func RuneLength(str string) int {
} }
// PascalCase converts string to pascal case. // PascalCase converts string to pascal case.
// Play: https://go.dev/play/p/Dy_V_6DUYhe
func PascalCase(str string) string { func PascalCase(str string) string {
items := Words(str) items := Words(str)
for i := range items { for i := range items {
@@ -160,6 +161,7 @@ func PascalCase(str string) string {
} }
// CamelCase converts string to camel case. // CamelCase converts string to camel case.
// Play: https://go.dev/play/p/Go6aKwUiq59
func CamelCase(str string) string { func CamelCase(str string) string {
items := Words(str) items := Words(str)
for i, item := range items { for i, item := range items {
@@ -173,6 +175,7 @@ func CamelCase(str string) string {
} }
// KebabCase converts string to kebab case. // KebabCase converts string to kebab case.
// Play: https://go.dev/play/p/96gT_WZnTVP
func KebabCase(str string) string { func KebabCase(str string) string {
items := Words(str) items := Words(str)
for i := range items { for i := range items {
@@ -182,6 +185,7 @@ func KebabCase(str string) string {
} }
// SnakeCase converts string to snake case. // SnakeCase converts string to snake case.
// Play: https://go.dev/play/p/ziB0V89IeVH
func SnakeCase(str string) string { func SnakeCase(str string) string {
items := Words(str) items := Words(str)
for i := range items { for i := range items {
@@ -191,6 +195,7 @@ func SnakeCase(str string) string {
} }
// Words splits string into an array of its words. // Words splits string into an array of its words.
// Play: https://go.dev/play/p/-f3VIQqiaVw
func Words(str string) []string { func Words(str string) []string {
str = splitWordReg.ReplaceAllString(str, `$1$3$5$7 $2$4$6$8$9`) str = splitWordReg.ReplaceAllString(str, `$1$3$5$7 $2$4$6$8$9`)
// example: Int8Value => Int 8Value => Int 8 Value // example: Int8Value => Int 8Value => Int 8 Value
@@ -207,6 +212,7 @@ func Words(str string) []string {
} }
// Capitalize converts the first character of string to upper case and the remaining to lower case. // Capitalize converts the first character of string to upper case and the remaining to lower case.
// Play: https://go.dev/play/p/uLTZZQXqnsa
func Capitalize(str string) string { func Capitalize(str string) string {
return cases.Title(language.English).String(str) return cases.Title(language.English).String(str)
} }
@@ -214,6 +220,7 @@ func Capitalize(str string) string {
// Ellipsis trims and truncates a string to a specified length **in bytes** and appends an ellipsis // Ellipsis trims and truncates a string to a specified length **in bytes** and appends an ellipsis
// if truncated. If the string contains non-ASCII characters (which may occupy multiple bytes in UTF-8), // if truncated. If the string contains non-ASCII characters (which may occupy multiple bytes in UTF-8),
// truncating by byte length may split a character in the middle, potentially resulting in garbled output. // truncating by byte length may split a character in the middle, potentially resulting in garbled output.
// Play: https://go.dev/play/p/qE93rgqe1TW
func Ellipsis(str string, length int) string { func Ellipsis(str string, length int) string {
str = strings.TrimSpace(str) str = strings.TrimSpace(str)

12
time.go
View File

@@ -3,11 +3,13 @@ package lo
import "time" import "time"
// Duration returns the time taken to execute a function. // Duration returns the time taken to execute a function.
// Play: https://go.dev/play/p/HQfbBbAXaFP
func Duration(cb func()) time.Duration { func Duration(cb func()) time.Duration {
return Duration0(cb) return Duration0(cb)
} }
// Duration0 returns the time taken to execute a function. // Duration0 returns the time taken to execute a function.
// Play: https://go.dev/play/p/HQfbBbAXaFP
func Duration0(cb func()) time.Duration { func Duration0(cb func()) time.Duration {
start := time.Now() start := time.Now()
cb() cb()
@@ -15,6 +17,7 @@ func Duration0(cb func()) time.Duration {
} }
// Duration1 returns the time taken to execute a function. // Duration1 returns the time taken to execute a function.
// Play: https://go.dev/play/p/HQfbBbAXaFP
func Duration1[A any](cb func() A) (A, time.Duration) { func Duration1[A any](cb func() A) (A, time.Duration) {
start := time.Now() start := time.Now()
a := cb() a := cb()
@@ -22,6 +25,7 @@ func Duration1[A any](cb func() A) (A, time.Duration) {
} }
// Duration2 returns the time taken to execute a function. // Duration2 returns the time taken to execute a function.
// Play: https://go.dev/play/p/HQfbBbAXaFP
func Duration2[A, B any](cb func() (A, B)) (A, B, time.Duration) { func Duration2[A, B any](cb func() (A, B)) (A, B, time.Duration) {
start := time.Now() start := time.Now()
a, b := cb() a, b := cb()
@@ -29,6 +33,7 @@ func Duration2[A, B any](cb func() (A, B)) (A, B, time.Duration) {
} }
// Duration3 returns the time taken to execute a function. // Duration3 returns the time taken to execute a function.
// Play: https://go.dev/play/p/xr863iwkAxQ
func Duration3[A, B, C any](cb func() (A, B, C)) (A, B, C, time.Duration) { func Duration3[A, B, C any](cb func() (A, B, C)) (A, B, C, time.Duration) {
start := time.Now() start := time.Now()
a, b, c := cb() a, b, c := cb()
@@ -36,6 +41,7 @@ func Duration3[A, B, C any](cb func() (A, B, C)) (A, B, C, time.Duration) {
} }
// Duration4 returns the time taken to execute a function. // Duration4 returns the time taken to execute a function.
// Play: https://go.dev/play/p/xr863iwkAxQ
func Duration4[A, B, C, D any](cb func() (A, B, C, D)) (A, B, C, D, time.Duration) { func Duration4[A, B, C, D any](cb func() (A, B, C, D)) (A, B, C, D, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d := cb() a, b, c, d := cb()
@@ -43,6 +49,7 @@ func Duration4[A, B, C, D any](cb func() (A, B, C, D)) (A, B, C, D, time.Duratio
} }
// Duration5 returns the time taken to execute a function. // Duration5 returns the time taken to execute a function.
// Play: https://go.dev/play/p/xr863iwkAxQ
func Duration5[A, B, C, D, E any](cb func() (A, B, C, D, E)) (A, B, C, D, E, time.Duration) { func Duration5[A, B, C, D, E any](cb func() (A, B, C, D, E)) (A, B, C, D, E, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e := cb() a, b, c, d, e := cb()
@@ -50,6 +57,7 @@ func Duration5[A, B, C, D, E any](cb func() (A, B, C, D, E)) (A, B, C, D, E, tim
} }
// Duration6 returns the time taken to execute a function. // Duration6 returns the time taken to execute a function.
// Play: https://go.dev/play/p/mR4bTQKO-Tf
func Duration6[A, B, C, D, E, F any](cb func() (A, B, C, D, E, F)) (A, B, C, D, E, F, time.Duration) { func Duration6[A, B, C, D, E, F any](cb func() (A, B, C, D, E, F)) (A, B, C, D, E, F, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e, f := cb() a, b, c, d, e, f := cb()
@@ -57,6 +65,7 @@ func Duration6[A, B, C, D, E, F any](cb func() (A, B, C, D, E, F)) (A, B, C, D,
} }
// Duration7 returns the time taken to execute a function. // Duration7 returns the time taken to execute a function.
// Play: https://go.dev/play/p/jgIAcBWWInS
func Duration7[A, B, C, D, E, F, G any](cb func() (A, B, C, D, E, F, G)) (A, B, C, D, E, F, G, time.Duration) { func Duration7[A, B, C, D, E, F, G any](cb func() (A, B, C, D, E, F, G)) (A, B, C, D, E, F, G, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e, f, g := cb() a, b, c, d, e, f, g := cb()
@@ -64,6 +73,7 @@ func Duration7[A, B, C, D, E, F, G any](cb func() (A, B, C, D, E, F, G)) (A, B,
} }
// Duration8 returns the time taken to execute a function. // Duration8 returns the time taken to execute a function.
// Play: https://go.dev/play/p/T8kxpG1c5Na
func Duration8[A, B, C, D, E, F, G, H any](cb func() (A, B, C, D, E, F, G, H)) (A, B, C, D, E, F, G, H, time.Duration) { func Duration8[A, B, C, D, E, F, G, H any](cb func() (A, B, C, D, E, F, G, H)) (A, B, C, D, E, F, G, H, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e, f, g, h := cb() a, b, c, d, e, f, g, h := cb()
@@ -71,6 +81,7 @@ func Duration8[A, B, C, D, E, F, G, H any](cb func() (A, B, C, D, E, F, G, H)) (
} }
// Duration9 returns the time taken to execute a function. // Duration9 returns the time taken to execute a function.
// Play: https://go.dev/play/p/bg9ix2VrZ0j
func Duration9[A, B, C, D, E, F, G, H, I any](cb func() (A, B, C, D, E, F, G, H, I)) (A, B, C, D, E, F, G, H, I, time.Duration) { func Duration9[A, B, C, D, E, F, G, H, I any](cb func() (A, B, C, D, E, F, G, H, I)) (A, B, C, D, E, F, G, H, I, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e, f, g, h, i := cb() a, b, c, d, e, f, g, h, i := cb()
@@ -78,6 +89,7 @@ func Duration9[A, B, C, D, E, F, G, H, I any](cb func() (A, B, C, D, E, F, G, H,
} }
// Duration10 returns the time taken to execute a function. // Duration10 returns the time taken to execute a function.
// Play: https://go.dev/play/p/Y3n7oJXqJbk
func Duration10[A, B, C, D, E, F, G, H, I, J any](cb func() (A, B, C, D, E, F, G, H, I, J)) (A, B, C, D, E, F, G, H, I, J, time.Duration) { func Duration10[A, B, C, D, E, F, G, H, I, J any](cb func() (A, B, C, D, E, F, G, H, I, J)) (A, B, C, D, E, F, G, H, I, J, time.Duration) {
start := time.Now() start := time.Now()
a, b, c, d, e, f, g, h, i, j := cb() a, b, c, d, e, f, g, h, i, j := cb()

View File

@@ -331,6 +331,7 @@ func Zip9[A, B, C, D, E, F, G, H, I any](a []A, b []B, c []C, d []D, e []E, f []
// ZipBy2 creates a slice of transformed elements, the first of which contains the first elements // ZipBy2 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/wlHur6yO8rR
func ZipBy2[A any, B any, Out any](a []A, b []B, iteratee func(a A, b B) Out) []Out { func ZipBy2[A any, B any, Out any](a []A, b []B, iteratee func(a A, b B) Out) []Out {
size := Max([]int{len(a), len(b)}) size := Max([]int{len(a), len(b)})
@@ -349,6 +350,7 @@ func ZipBy2[A any, B any, Out any](a []A, b []B, iteratee func(a A, b B) Out) []
// ZipBy3 creates a slice of transformed elements, the first of which contains the first elements // ZipBy3 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/j9maveOnSQX
func ZipBy3[A any, B any, C any, Out any](a []A, b []B, c []C, iteratee func(a A, b B, c C) Out) []Out { func ZipBy3[A any, B any, C any, Out any](a []A, b []B, c []C, iteratee func(a A, b B, c C) Out) []Out {
size := Max([]int{len(a), len(b), len(c)}) size := Max([]int{len(a), len(b), len(c)})
@@ -368,6 +370,7 @@ func ZipBy3[A any, B any, C any, Out any](a []A, b []B, c []C, iteratee func(a A
// ZipBy4 creates a slice of transformed elements, the first of which contains the first elements // ZipBy4 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/Y1eF2Ke0Ayz
func ZipBy4[A any, B any, C any, D any, Out any](a []A, b []B, c []C, d []D, iteratee func(a A, b B, c C, d D) Out) []Out { func ZipBy4[A any, B any, C any, D any, Out any](a []A, b []B, c []C, d []D, iteratee func(a A, b B, c C, d D) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d)}) size := Max([]int{len(a), len(b), len(c), len(d)})
@@ -388,6 +391,7 @@ func ZipBy4[A any, B any, C any, D any, Out any](a []A, b []B, c []C, d []D, ite
// ZipBy5 creates a slice of transformed elements, the first of which contains the first elements // ZipBy5 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/SLynyalh5Oa
func ZipBy5[A any, B any, C any, D any, E any, Out any](a []A, b []B, c []C, d []D, e []E, iteratee func(a A, b B, c C, d D, e E) Out) []Out { func ZipBy5[A any, B any, C any, D any, E any, Out any](a []A, b []B, c []C, d []D, e []E, iteratee func(a A, b B, c C, d D, e E) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d), len(e)}) size := Max([]int{len(a), len(b), len(c), len(d), len(e)})
@@ -409,6 +413,7 @@ func ZipBy5[A any, B any, C any, D any, E any, Out any](a []A, b []B, c []C, d [
// ZipBy6 creates a slice of transformed elements, the first of which contains the first elements // ZipBy6 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/IK6KVgw9e-S
func ZipBy6[A any, B any, C any, D any, E any, F any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, iteratee func(a A, b B, c C, d D, e E, f F) Out) []Out { func ZipBy6[A any, B any, C any, D any, E any, F any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, iteratee func(a A, b B, c C, d D, e E, f F) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f)}) size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f)})
@@ -431,6 +436,7 @@ func ZipBy6[A any, B any, C any, D any, E any, F any, Out any](a []A, b []B, c [
// ZipBy7 creates a slice of transformed elements, the first of which contains the first elements // ZipBy7 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/4uW6a2vXh8w
func ZipBy7[A any, B any, C any, D any, E any, F any, G any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, iteratee func(a A, b B, c C, d D, e E, f F, g G) Out) []Out { func ZipBy7[A any, B any, C any, D any, E any, F any, G any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, iteratee func(a A, b B, c C, d D, e E, f F, g G) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)}) size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g)})
@@ -454,6 +460,7 @@ func ZipBy7[A any, B any, C any, D any, E any, F any, G any, Out any](a []A, b [
// ZipBy8 creates a slice of transformed elements, the first of which contains the first elements // ZipBy8 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/tk8xW7XzY4v
func ZipBy8[A any, B any, C any, D any, E any, F any, G any, H any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out { func ZipBy8[A any, B any, C any, D any, E any, F any, G any, H any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h)}) size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h)})
@@ -478,6 +485,7 @@ func ZipBy8[A any, B any, C any, D any, E any, F any, G any, H any, Out any](a [
// ZipBy9 creates a slice of transformed elements, the first of which contains the first elements // ZipBy9 creates a slice of transformed elements, the first of which contains the first elements
// of the given arrays, the second of which contains the second elements of the given arrays, and so on. // of the given arrays, the second of which contains the second elements of the given arrays, and so on.
// When collections have different size, the Tuple attributes are filled with zero value. // When collections have different size, the Tuple attributes are filled with zero value.
// Play: https://go.dev/play/p/VGqjDmQ9YqX
func ZipBy9[A any, B any, C any, D any, E any, F any, G any, H any, I any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out { func ZipBy9[A any, B any, C any, D any, E any, F any, G any, H any, I any, Out any](a []A, b []B, c []C, d []D, e []E, f []F, g []G, h []H, i []I, iteratee func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out {
size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)}) size := Max([]int{len(a), len(b), len(c), len(d), len(e), len(f), len(g), len(h), len(i)})
@@ -686,6 +694,7 @@ func Unzip9[A, B, C, D, E, F, G, H, I any](tuples []Tuple9[A, B, C, D, E, F, G,
// UnzipBy2 iterates over a collection and creates an array regrouping the elements // UnzipBy2 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/tN8yqaRZz0r
func UnzipBy2[In any, A any, B any](items []In, iteratee func(In) (a A, b B)) ([]A, []B) { func UnzipBy2[In any, A any, B any](items []In, iteratee func(In) (a A, b B)) ([]A, []B) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -702,6 +711,7 @@ func UnzipBy2[In any, A any, B any](items []In, iteratee func(In) (a A, b B)) ([
// UnzipBy3 iterates over a collection and creates an array regrouping the elements // UnzipBy3 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/36ITO2DlQq1
func UnzipBy3[In any, A any, B any, C any](items []In, iteratee func(In) (a A, b B, c C)) ([]A, []B, []C) { func UnzipBy3[In any, A any, B any, C any](items []In, iteratee func(In) (a A, b B, c C)) ([]A, []B, []C) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -720,6 +730,7 @@ func UnzipBy3[In any, A any, B any, C any](items []In, iteratee func(In) (a A, b
// UnzipBy4 iterates over a collection and creates an array regrouping the elements // UnzipBy4 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/zJ6qY1dD1rL
func UnzipBy4[In any, A any, B any, C any, D any](items []In, iteratee func(In) (a A, b B, c C, d D)) ([]A, []B, []C, []D) { func UnzipBy4[In any, A any, B any, C any, D any](items []In, iteratee func(In) (a A, b B, c C, d D)) ([]A, []B, []C, []D) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -740,6 +751,7 @@ func UnzipBy4[In any, A any, B any, C any, D any](items []In, iteratee func(In)
// UnzipBy5 iterates over a collection and creates an array regrouping the elements // UnzipBy5 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/3f7jKkV9xZt
func UnzipBy5[In any, A any, B any, C any, D any, E any](items []In, iteratee func(In) (a A, b B, c C, d D, e E)) ([]A, []B, []C, []D, []E) { func UnzipBy5[In any, A any, B any, C any, D any, E any](items []In, iteratee func(In) (a A, b B, c C, d D, e E)) ([]A, []B, []C, []D, []E) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -762,6 +774,7 @@ func UnzipBy5[In any, A any, B any, C any, D any, E any](items []In, iteratee fu
// UnzipBy6 iterates over a collection and creates an array regrouping the elements // UnzipBy6 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/8Y1b7tKu2pL
func UnzipBy6[In any, A any, B any, C any, D any, E any, F any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F)) ([]A, []B, []C, []D, []E, []F) { func UnzipBy6[In any, A any, B any, C any, D any, E any, F any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F)) ([]A, []B, []C, []D, []E, []F) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -786,6 +799,7 @@ func UnzipBy6[In any, A any, B any, C any, D any, E any, F any](items []In, iter
// UnzipBy7 iterates over a collection and creates an array regrouping the elements // UnzipBy7 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/7j1kLmVn3pM
func UnzipBy7[In any, A any, B any, C any, D any, E any, F any, G any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G)) ([]A, []B, []C, []D, []E, []F, []G) { func UnzipBy7[In any, A any, B any, C any, D any, E any, F any, G any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G)) ([]A, []B, []C, []D, []E, []F, []G) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -812,6 +826,7 @@ func UnzipBy7[In any, A any, B any, C any, D any, E any, F any, G any](items []I
// UnzipBy8 iterates over a collection and creates an array regrouping the elements // UnzipBy8 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/1n2k3L4m5N6
func UnzipBy8[In any, A any, B any, C any, D any, E any, F any, G any, H any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H)) ([]A, []B, []C, []D, []E, []F, []G, []H) { func UnzipBy8[In any, A any, B any, C any, D any, E any, F any, G any, H any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H)) ([]A, []B, []C, []D, []E, []F, []G, []H) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -840,6 +855,7 @@ func UnzipBy8[In any, A any, B any, C any, D any, E any, F any, G any, H any](it
// UnzipBy9 iterates over a collection and creates an array regrouping the elements // UnzipBy9 iterates over a collection and creates an array regrouping the elements
// to their pre-zip configuration. // to their pre-zip configuration.
// Play: https://go.dev/play/p/7o8p9q0r1s2
func UnzipBy9[In any, A any, B any, C any, D any, E any, F any, G any, H any, I any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H, i I)) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) { func UnzipBy9[In any, A any, B any, C any, D any, E any, F any, G any, H any, I any](items []In, iteratee func(In) (a A, b B, c C, d D, e E, f F, g G, h H, i I)) ([]A, []B, []C, []D, []E, []F, []G, []H, []I) {
size := len(items) size := len(items)
r1 := make([]A, 0, size) r1 := make([]A, 0, size)
@@ -871,6 +887,7 @@ func UnzipBy9[In any, A any, B any, C any, D any, E any, F any, G any, H any, I
// CrossJoin2 combines every items from one list with every items from others. // CrossJoin2 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/3VFppyL9FDU
func CrossJoin2[A, B any](listA []A, listB []B) []Tuple2[A, B] { func CrossJoin2[A, B any](listA []A, listB []B) []Tuple2[A, B] {
return CrossJoinBy2(listA, listB, T2[A, B]) return CrossJoinBy2(listA, listB, T2[A, B])
} }
@@ -878,6 +895,7 @@ func CrossJoin2[A, B any](listA []A, listB []B) []Tuple2[A, B] {
// CrossJoin3 combines every items from one list with every items from others. // CrossJoin3 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/2WGeHyJj4fK
func CrossJoin3[A, B, C any](listA []A, listB []B, listC []C) []Tuple3[A, B, C] { func CrossJoin3[A, B, C any](listA []A, listB []B, listC []C) []Tuple3[A, B, C] {
return CrossJoinBy3(listA, listB, listC, T3[A, B, C]) return CrossJoinBy3(listA, listB, listC, T3[A, B, C])
} }
@@ -885,6 +903,7 @@ func CrossJoin3[A, B, C any](listA []A, listB []B, listC []C) []Tuple3[A, B, C]
// CrossJoin4 combines every items from one list with every items from others. // CrossJoin4 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/6XhKjLmMnNp
func CrossJoin4[A, B, C, D any](listA []A, listB []B, listC []C, listD []D) []Tuple4[A, B, C, D] { func CrossJoin4[A, B, C, D any](listA []A, listB []B, listC []C, listD []D) []Tuple4[A, B, C, D] {
return CrossJoinBy4(listA, listB, listC, listD, T4[A, B, C, D]) return CrossJoinBy4(listA, listB, listC, listD, T4[A, B, C, D])
} }
@@ -892,6 +911,7 @@ func CrossJoin4[A, B, C, D any](listA []A, listB []B, listC []C, listD []D) []Tu
// CrossJoin5 combines every items from one list with every items from others. // CrossJoin5 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/7oPqRsTuVwX
func CrossJoin5[A, B, C, D, E any](listA []A, listB []B, listC []C, listD []D, listE []E) []Tuple5[A, B, C, D, E] { func CrossJoin5[A, B, C, D, E any](listA []A, listB []B, listC []C, listD []D, listE []E) []Tuple5[A, B, C, D, E] {
return CrossJoinBy5(listA, listB, listC, listD, listE, T5[A, B, C, D, E]) return CrossJoinBy5(listA, listB, listC, listD, listE, T5[A, B, C, D, E])
} }
@@ -899,6 +919,7 @@ func CrossJoin5[A, B, C, D, E any](listA []A, listB []B, listC []C, listD []D, l
// CrossJoin6 combines every items from one list with every items from others. // CrossJoin6 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/8yZ1aB2cD3e
func CrossJoin6[A, B, C, D, E, F any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F) []Tuple6[A, B, C, D, E, F] { func CrossJoin6[A, B, C, D, E, F any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F) []Tuple6[A, B, C, D, E, F] {
return CrossJoinBy6(listA, listB, listC, listD, listE, listF, T6[A, B, C, D, E, F]) return CrossJoinBy6(listA, listB, listC, listD, listE, listF, T6[A, B, C, D, E, F])
} }
@@ -906,6 +927,7 @@ func CrossJoin6[A, B, C, D, E, F any](listA []A, listB []B, listC []C, listD []D
// CrossJoin7 combines every items from one list with every items from others. // CrossJoin7 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/9f4g5h6i7j8
func CrossJoin7[A, B, C, D, E, F, G any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G) []Tuple7[A, B, C, D, E, F, G] { func CrossJoin7[A, B, C, D, E, F, G any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G) []Tuple7[A, B, C, D, E, F, G] {
return CrossJoinBy7(listA, listB, listC, listD, listE, listF, listG, T7[A, B, C, D, E, F, G]) return CrossJoinBy7(listA, listB, listC, listD, listE, listF, listG, T7[A, B, C, D, E, F, G])
} }
@@ -913,6 +935,7 @@ func CrossJoin7[A, B, C, D, E, F, G any](listA []A, listB []B, listC []C, listD
// CrossJoin8 combines every items from one list with every items from others. // CrossJoin8 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/0k1l2m3n4o5
func CrossJoin8[A, B, C, D, E, F, G, H any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H) []Tuple8[A, B, C, D, E, F, G, H] { func CrossJoin8[A, B, C, D, E, F, G, H any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H) []Tuple8[A, B, C, D, E, F, G, H] {
return CrossJoinBy8(listA, listB, listC, listD, listE, listF, listG, listH, T8[A, B, C, D, E, F, G, H]) return CrossJoinBy8(listA, listB, listC, listD, listE, listF, listG, listH, T8[A, B, C, D, E, F, G, H])
} }
@@ -920,6 +943,7 @@ func CrossJoin8[A, B, C, D, E, F, G, H any](listA []A, listB []B, listC []C, lis
// CrossJoin9 combines every items from one list with every items from others. // CrossJoin9 combines every items from one list with every items from others.
// It is the cartesian product of lists received as arguments. // It is the cartesian product of lists received as arguments.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/6p7q8r9s0t1
func CrossJoin9[A, B, C, D, E, F, G, H, I any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I) []Tuple9[A, B, C, D, E, F, G, H, I] { func CrossJoin9[A, B, C, D, E, F, G, H, I any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I) []Tuple9[A, B, C, D, E, F, G, H, I] {
return CrossJoinBy9(listA, listB, listC, listD, listE, listF, listG, listH, listI, T9[A, B, C, D, E, F, G, H, I]) return CrossJoinBy9(listA, listB, listC, listD, listE, listF, listG, listH, listI, T9[A, B, C, D, E, F, G, H, I])
} }
@@ -928,6 +952,7 @@ func CrossJoin9[A, B, C, D, E, F, G, H, I any](listA []A, listB []B, listC []C,
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/8Y7btpvuA-C
func CrossJoinBy2[A, B, Out any](listA []A, listB []B, project func(a A, b B) Out) []Out { func CrossJoinBy2[A, B, Out any](listA []A, listB []B, project func(a A, b B) Out) []Out {
size := len(listA) * len(listB) size := len(listA) * len(listB)
if size == 0 { if size == 0 {
@@ -949,6 +974,7 @@ func CrossJoinBy2[A, B, Out any](listA []A, listB []B, project func(a A, b B) Ou
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/3z4y5x6w7v8
func CrossJoinBy3[A, B, C, Out any](listA []A, listB []B, listC []C, project func(a A, b B, c C) Out) []Out { func CrossJoinBy3[A, B, C, Out any](listA []A, listB []B, listC []C, project func(a A, b B, c C) Out) []Out {
size := len(listA) * len(listB) * len(listC) size := len(listA) * len(listB) * len(listC)
if size == 0 { if size == 0 {
@@ -972,6 +998,7 @@ func CrossJoinBy3[A, B, C, Out any](listA []A, listB []B, listC []C, project fun
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/8b9c0d1e2f3
func CrossJoinBy4[A, B, C, D, Out any](listA []A, listB []B, listC []C, listD []D, project func(a A, b B, c C, d D) Out) []Out { func CrossJoinBy4[A, B, C, D, Out any](listA []A, listB []B, listC []C, listD []D, project func(a A, b B, c C, d D) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) size := len(listA) * len(listB) * len(listC) * len(listD)
if size == 0 { if size == 0 {
@@ -997,6 +1024,7 @@ func CrossJoinBy4[A, B, C, D, Out any](listA []A, listB []B, listC []C, listD []
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/4g5h6i7j8k9
func CrossJoinBy5[A, B, C, D, E, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, project func(a A, b B, c C, d D, e E) Out) []Out { func CrossJoinBy5[A, B, C, D, E, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, project func(a A, b B, c C, d D, e E) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE)
if size == 0 { if size == 0 {
@@ -1024,6 +1052,7 @@ func CrossJoinBy5[A, B, C, D, E, Out any](listA []A, listB []B, listC []C, listD
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/1l2m3n4o5p6
func CrossJoinBy6[A, B, C, D, E, F, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, project func(a A, b B, c C, d D, e E, f F) Out) []Out { func CrossJoinBy6[A, B, C, D, E, F, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, project func(a A, b B, c C, d D, e E, f F) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF)
if size == 0 { if size == 0 {
@@ -1053,6 +1082,7 @@ func CrossJoinBy6[A, B, C, D, E, F, Out any](listA []A, listB []B, listC []C, li
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/7q8r9s0t1u2
func CrossJoinBy7[A, B, C, D, E, F, G, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, project func(a A, b B, c C, d D, e E, f F, g G) Out) []Out { func CrossJoinBy7[A, B, C, D, E, F, G, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, project func(a A, b B, c C, d D, e E, f F, g G) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG)
if size == 0 { if size == 0 {
@@ -1084,6 +1114,7 @@ func CrossJoinBy7[A, B, C, D, E, F, G, Out any](listA []A, listB []B, listC []C,
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/3v4w5x6y7z8
func CrossJoinBy8[A, B, C, D, E, F, G, H, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, project func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out { func CrossJoinBy8[A, B, C, D, E, F, G, H, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, project func(a A, b B, c C, d D, e E, f F, g G, h H) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH)
if size == 0 { if size == 0 {
@@ -1117,6 +1148,7 @@ func CrossJoinBy8[A, B, C, D, E, F, G, H, Out any](listA []A, listB []B, listC [
// It is the cartesian product of lists received as arguments. The project function // It is the cartesian product of lists received as arguments. The project function
// is used to create the output values. // is used to create the output values.
// It returns an empty list if a list is empty. // It returns an empty list if a list is empty.
// Play: https://go.dev/play/p/9a0b1c2d3e4
func CrossJoinBy9[A, B, C, D, E, F, G, H, I, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I, project func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out { func CrossJoinBy9[A, B, C, D, E, F, G, H, I, Out any](listA []A, listB []B, listC []C, listD []D, listE []E, listF []F, listG []G, listH []H, listI []I, project func(a A, b B, c C, d D, e E, f F, g G, h H, i I) Out) []Out {
size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) * len(listI) size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) * len(listI)
if size == 0 { if size == 0 {

View File

@@ -3,28 +3,33 @@ package lo
import "reflect" import "reflect"
// IsNil checks if a value is nil or if it's a reference type with a nil underlying value. // IsNil checks if a value is nil or if it's a reference type with a nil underlying value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func IsNil(x any) bool { func IsNil(x any) bool {
defer func() { recover() }() // nolint:errcheck defer func() { recover() }() // nolint:errcheck
return x == nil || reflect.ValueOf(x).IsNil() return x == nil || reflect.ValueOf(x).IsNil()
} }
// IsNotNil checks if a value is not nil or if it's not a reference type with a nil underlying value. // IsNotNil checks if a value is not nil or if it's not a reference type with a nil underlying value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func IsNotNil(x any) bool { func IsNotNil(x any) bool {
return !IsNil(x) return !IsNil(x)
} }
// ToPtr returns a pointer copy of value. // ToPtr returns a pointer copy of value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func ToPtr[T any](x T) *T { func ToPtr[T any](x T) *T {
return &x return &x
} }
// Nil returns a nil pointer of type. // Nil returns a nil pointer of type.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func Nil[T any]() *T { func Nil[T any]() *T {
return nil return nil
} }
// EmptyableToPtr returns a pointer copy of value if it's nonzero. // EmptyableToPtr returns a pointer copy of value if it's nonzero.
// Otherwise, returns nil pointer. // Otherwise, returns nil pointer.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func EmptyableToPtr[T any](x T) *T { func EmptyableToPtr[T any](x T) *T {
// 🤮 // 🤮
isZero := reflect.ValueOf(&x).Elem().IsZero() isZero := reflect.ValueOf(&x).Elem().IsZero()
@@ -36,6 +41,7 @@ func EmptyableToPtr[T any](x T) *T {
} }
// FromPtr returns the pointer value or empty. // FromPtr returns the pointer value or empty.
// Play: https://go.dev/play/p/mhD9CwO3X0m
func FromPtr[T any](x *T) T { func FromPtr[T any](x *T) T {
if x == nil { if x == nil {
return Empty[T]() return Empty[T]()
@@ -45,6 +51,7 @@ func FromPtr[T any](x *T) T {
} }
// FromPtrOr returns the pointer value or the fallback value. // FromPtrOr returns the pointer value or the fallback value.
// Play: https://go.dev/play/p/mhD9CwO3X0m
func FromPtrOr[T any](x *T, fallback T) T { func FromPtrOr[T any](x *T, fallback T) T {
if x == nil { if x == nil {
return fallback return fallback
@@ -54,6 +61,7 @@ func FromPtrOr[T any](x *T, fallback T) T {
} }
// ToSlicePtr returns a slice of pointer copy of value. // ToSlicePtr returns a slice of pointer copy of value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func ToSlicePtr[T any](collection []T) []*T { func ToSlicePtr[T any](collection []T) []*T {
result := make([]*T, len(collection)) result := make([]*T, len(collection))
@@ -65,6 +73,7 @@ func ToSlicePtr[T any](collection []T) []*T {
// FromSlicePtr returns a slice with the pointer values. // FromSlicePtr returns a slice with the pointer values.
// Returns a zero value in case of a nil pointer element. // Returns a zero value in case of a nil pointer element.
// Play: https://go.dev/play/p/lbunFvzlUDX
func FromSlicePtr[T any](collection []*T) []T { func FromSlicePtr[T any](collection []*T) []T {
return Map(collection, func(x *T, _ int) T { return Map(collection, func(x *T, _ int) T {
if x == nil { if x == nil {
@@ -86,6 +95,7 @@ func FromSlicePtrOr[T any](collection []*T, fallback T) []T {
} }
// ToAnySlice returns a slice with all elements mapped to `any` type // ToAnySlice returns a slice with all elements mapped to `any` type
// Play: https://go.dev/play/p/P2sD0PMXw4F
func ToAnySlice[T any](collection []T) []any { func ToAnySlice[T any](collection []T) []any {
result := make([]any, len(collection)) result := make([]any, len(collection))
for i := range collection { for i := range collection {
@@ -96,6 +106,7 @@ func ToAnySlice[T any](collection []T) []any {
// FromAnySlice returns an `any` slice with all elements mapped to a type. // FromAnySlice returns an `any` slice with all elements mapped to a type.
// Returns false in case of type conversion failure. // Returns false in case of type conversion failure.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func FromAnySlice[T any](in []any) (out []T, ok bool) { func FromAnySlice[T any](in []any) (out []T, ok bool) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@@ -112,24 +123,28 @@ func FromAnySlice[T any](in []any) (out []T, ok bool) {
} }
// Empty returns the zero value (https://go.dev/ref/spec#The_zero_value). // Empty returns the zero value (https://go.dev/ref/spec#The_zero_value).
// Play: https://go.dev/play/p/P2sD0PMXw4F
func Empty[T any]() T { func Empty[T any]() T {
var zero T var zero T
return zero return zero
} }
// IsEmpty returns true if argument is a zero value. // IsEmpty returns true if argument is a zero value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func IsEmpty[T comparable](v T) bool { func IsEmpty[T comparable](v T) bool {
var zero T var zero T
return zero == v return zero == v
} }
// IsNotEmpty returns true if argument is not a zero value. // IsNotEmpty returns true if argument is not a zero value.
// Play: https://go.dev/play/p/P2sD0PMXw4F
func IsNotEmpty[T comparable](v T) bool { func IsNotEmpty[T comparable](v T) bool {
var zero T var zero T
return zero != v return zero != v
} }
// Coalesce returns the first non-empty arguments. Arguments must be comparable. // Coalesce returns the first non-empty arguments. Arguments must be comparable.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func Coalesce[T comparable](values ...T) (result T, ok bool) { func Coalesce[T comparable](values ...T) (result T, ok bool) {
for i := range values { for i := range values {
if values[i] != result { if values[i] != result {
@@ -143,12 +158,14 @@ func Coalesce[T comparable](values ...T) (result T, ok bool) {
} }
// CoalesceOrEmpty returns the first non-empty arguments. Arguments must be comparable. // CoalesceOrEmpty returns the first non-empty arguments. Arguments must be comparable.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func CoalesceOrEmpty[T comparable](v ...T) T { func CoalesceOrEmpty[T comparable](v ...T) T {
result, _ := Coalesce(v...) result, _ := Coalesce(v...)
return result return result
} }
// CoalesceSlice returns the first non-zero slice. // CoalesceSlice returns the first non-zero slice.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func CoalesceSlice[T any](v ...[]T) ([]T, bool) { func CoalesceSlice[T any](v ...[]T) ([]T, bool) {
for i := range v { for i := range v {
if v[i] != nil && len(v[i]) > 0 { if v[i] != nil && len(v[i]) > 0 {
@@ -159,6 +176,7 @@ func CoalesceSlice[T any](v ...[]T) ([]T, bool) {
} }
// CoalesceSliceOrEmpty returns the first non-zero slice. // CoalesceSliceOrEmpty returns the first non-zero slice.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func CoalesceSliceOrEmpty[T any](v ...[]T) []T { func CoalesceSliceOrEmpty[T any](v ...[]T) []T {
for i := range v { for i := range v {
if v[i] != nil && len(v[i]) > 0 { if v[i] != nil && len(v[i]) > 0 {
@@ -169,6 +187,7 @@ func CoalesceSliceOrEmpty[T any](v ...[]T) []T {
} }
// CoalesceMap returns the first non-zero map. // CoalesceMap returns the first non-zero map.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func CoalesceMap[K comparable, V any](v ...map[K]V) (map[K]V, bool) { func CoalesceMap[K comparable, V any](v ...map[K]V) (map[K]V, bool) {
for i := range v { for i := range v {
if v[i] != nil && len(v[i]) > 0 { if v[i] != nil && len(v[i]) > 0 {
@@ -179,6 +198,7 @@ func CoalesceMap[K comparable, V any](v ...map[K]V) (map[K]V, bool) {
} }
// CoalesceMapOrEmpty returns the first non-zero map. // CoalesceMapOrEmpty returns the first non-zero map.
// Play: https://go.dev/play/p/Gyo9otyvFHH
func CoalesceMapOrEmpty[K comparable, V any](v ...map[K]V) map[K]V { func CoalesceMapOrEmpty[K comparable, V any](v ...map[K]V) map[K]V {
for i := range v { for i := range v {
if v[i] != nil && len(v[i]) > 0 { if v[i] != nil && len(v[i]) > 0 {

View File

@@ -13,6 +13,7 @@ type Tuple2[A, B any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/yrtn7QJTmL_E
func (t Tuple2[A, B]) Unpack() (A, B) { func (t Tuple2[A, B]) Unpack() (A, B) {
return t.A, t.B return t.A, t.B
} }
@@ -25,6 +26,7 @@ type Tuple3[A, B, C any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/yrtn7QJTmL_E
func (t Tuple3[A, B, C]) Unpack() (A, B, C) { func (t Tuple3[A, B, C]) Unpack() (A, B, C) {
return t.A, t.B, t.C return t.A, t.B, t.C
} }
@@ -38,6 +40,7 @@ type Tuple4[A, B, C, D any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/yrtn7QJTmL_E
func (t Tuple4[A, B, C, D]) Unpack() (A, B, C, D) { func (t Tuple4[A, B, C, D]) Unpack() (A, B, C, D) {
return t.A, t.B, t.C, t.D return t.A, t.B, t.C, t.D
} }
@@ -52,6 +55,7 @@ type Tuple5[A, B, C, D, E any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/7J4KrtgtK3M
func (t Tuple5[A, B, C, D, E]) Unpack() (A, B, C, D, E) { func (t Tuple5[A, B, C, D, E]) Unpack() (A, B, C, D, E) {
return t.A, t.B, t.C, t.D, t.E return t.A, t.B, t.C, t.D, t.E
} }
@@ -67,6 +71,7 @@ type Tuple6[A, B, C, D, E, F any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/7J4KrtgtK3M
func (t Tuple6[A, B, C, D, E, F]) Unpack() (A, B, C, D, E, F) { func (t Tuple6[A, B, C, D, E, F]) Unpack() (A, B, C, D, E, F) {
return t.A, t.B, t.C, t.D, t.E, t.F return t.A, t.B, t.C, t.D, t.E, t.F
} }
@@ -83,6 +88,7 @@ type Tuple7[A, B, C, D, E, F, G any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/Ow9Zgf_zeiA
func (t Tuple7[A, B, C, D, E, F, G]) Unpack() (A, B, C, D, E, F, G) { func (t Tuple7[A, B, C, D, E, F, G]) Unpack() (A, B, C, D, E, F, G) {
return t.A, t.B, t.C, t.D, t.E, t.F, t.G return t.A, t.B, t.C, t.D, t.E, t.F, t.G
} }
@@ -100,6 +106,7 @@ type Tuple8[A, B, C, D, E, F, G, H any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/Ow9Zgf_zeiA
func (t Tuple8[A, B, C, D, E, F, G, H]) Unpack() (A, B, C, D, E, F, G, H) { func (t Tuple8[A, B, C, D, E, F, G, H]) Unpack() (A, B, C, D, E, F, G, H) {
return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H
} }
@@ -118,6 +125,7 @@ type Tuple9[A, B, C, D, E, F, G, H, I any] struct {
} }
// Unpack returns values contained in tuple. // Unpack returns values contained in tuple.
// Play: https://go.dev/play/p/Ow9Zgf_zeiA
func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unpack() (A, B, C, D, E, F, G, H, I) { func (t Tuple9[A, B, C, D, E, F, G, H, I]) Unpack() (A, B, C, D, E, F, G, H, I) {
return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H, t.I return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H, t.I
} }