diff --git a/README.md b/README.md index f5047cb..c5498d4 100644 --- a/README.md +++ b/README.md @@ -392,6 +392,8 @@ lop.Map([]int64{1, 2, 3, 4}, func(x int64, _ int) string { // []string{"1", "2", "3", "4"} ``` +[[play](https://go.dev/play/p/sCJaB3quRMC)] + Mutable: like `lo.Map()`, but the slice is updated in place. ```go @@ -404,6 +406,8 @@ lom.Map(list, func(x int) int { // []int{2, 4, 6, 8} ``` +[[play](https://go.dev/play/p/0jY3Z0B7O_5)] + ### UniqMap 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"} ``` +[[play](https://go.dev/play/p/fygzLBhvUdB)] + ### FilterMap 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}} ``` +[[play](https://go.dev/play/p/iMeruQ3_W80)] + ### 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. @@ -634,7 +642,7 @@ lo.Chunk([]int{0}, 2) // [][]int{{0}} ``` -[[play](https://go.dev/play/p/EeKl0AuTehH)] +[[play](https://go.dev/play/p/kEMkFbdu85g)] ### PartitionBy @@ -853,6 +861,8 @@ result := lo.FilterSliceToMap(list, func(str string) (string, int, bool) { // map[string][int]{"aa":2 "aaa":3} ``` +[[play](https://go.dev/play/p/2z0rDz2ZSGU)] + ### Keyify 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:{}} ``` +[[play](https://go.dev/play/p/RYhhM_csqIG)] + ### Drop 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) @@ -1678,6 +1690,8 @@ mean := lo.MeanBy([]float64{}, mapper) // 0 ``` +[[play](https://go.dev/play/p/j7TsVwBOZ7P)] + ### Mode @@ -1773,7 +1787,7 @@ str := lo.PascalCase("hello_world") // HelloWorld ``` -[[play](https://go.dev/play/p/iZkdeLP9oiB)] +[[play](https://go.dev/play/p/Dy_V_6DUYhe)] ### CamelCase @@ -1784,7 +1798,7 @@ str := lo.CamelCase("hello_world") // helloWorld ``` -[[play](https://go.dev/play/p/dtyFB58MBRp)] +[[play](https://go.dev/play/p/Go6aKwUiq59)] ### KebabCase @@ -1795,7 +1809,7 @@ str := lo.KebabCase("helloWorld") // hello-world ``` -[[play](https://go.dev/play/p/2YTuPafwECA)] +[[play](https://go.dev/play/p/96gT_WZnTVP)] ### SnakeCase @@ -1806,7 +1820,7 @@ str := lo.SnakeCase("HelloWorld") // hello_world ``` -[[play](https://go.dev/play/p/QVKJG9nOnDg)] +[[play](https://go.dev/play/p/ziB0V89IeVH)] ### Words @@ -1817,7 +1831,7 @@ str := lo.Words("helloWorld") // []string{"hello", "world"} ``` -[[play](https://go.dev/play/p/2P4zhqqq61g)] +[[play](https://go.dev/play/p/-f3VIQqiaVw)] ### Capitalize @@ -1828,6 +1842,8 @@ str := lo.Capitalize("heLLO") // Hello ``` +[[play](https://go.dev/play/p/uLTZZQXqnsa)] + ### 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. @@ -1843,6 +1859,8 @@ str := lo.Ellipsis("Lorem Ipsum", 3) // ... ``` +[[play](https://go.dev/play/p/qE93rgqe1TW)] + ### T2 -> T9 Creates a tuple from a list of values. @@ -1968,6 +1986,8 @@ duration := lo.Duration(func() { // 3s ``` +[[play](https://go.dev/play/p/HQfbBbAXaFP)] + ### Duration0 -> Duration10 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: - [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 ``` +[[play](https://go.dev/play/p/lIbSY3QmiEg)] + ### ChannelToSlice 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 ``` +[[play](https://go.dev/play/p/W1EvyqY6t9j)] + ### ContainsBy Returns true if the predicate function returns `true`. @@ -2308,6 +2334,8 @@ b := EveryBy([]int{1, 2, 3, 4}, func(x int) bool { // true ``` +[[play](https://go.dev/play/p/dn1-vhHsq9x)] + ### Some 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 ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{0, 6}) // true +``` + +[[play](https://go.dev/play/p/Lj4ceFkeT9V)] ok := lo.Some([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) // false @@ -2344,6 +2375,8 @@ b := None([]int{0, 1, 2, 3, 4, 5}, []int{-1, 6}) // true ``` +[[play](https://go.dev/play/p/fye7JsmxzPV)] + ### NoneBy 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 ``` +[[play](https://go.dev/play/p/O64WZ32H58S)] + ### Intersect 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{} ``` +[[play](https://go.dev/play/p/pKE-JgzqRpz)] + ### Union 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 ``` +[[play](https://go.dev/play/p/Eo7W0lvKTky)] + ### 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. @@ -2527,6 +2566,8 @@ str, ok := lo.Find([]string{"foobar"}, func(i string) bool { // "", false ``` +[[play](https://go.dev/play/p/Eo7W0lvKTky)] + ### 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. @@ -2543,6 +2584,8 @@ str, index, ok := lo.FindIndexOf([]string{"foobar"}, func(i string) bool { // "", -1, false ``` +[[play](https://go.dev/play/p/XWSEM4Ic_t0)] + ### 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. @@ -2559,6 +2602,8 @@ str, index, ok := lo.FindLastIndexOf([]string{"foobar"}, func(i string) bool { // "", -1, false ``` +[[play](https://go.dev/play/p/dPiMRtJ6cUx)] + ### FindOrElse 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 ``` +[[play](https://go.dev/play/p/r6e-Z8JozS8)] + ### MinIndex 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 @@ -3215,6 +3264,8 @@ ptr := lo.ToPtr("hello world") // *string{"hello world"} ``` +[[play](https://go.dev/play/p/P2sD0PMXw4F)] + ### Nil Returns a nil pointer of type. @@ -3503,6 +3554,8 @@ f(42) // 47 ``` +[[play](https://go.dev/play/p/Sy1gAQiQZ3v)] + ### Partial2 -> Partial5 Returns new function that, when called, has its first argument set to the provided value. @@ -3518,6 +3571,8 @@ f(42, -4) // 80 ``` +[[play](https://go.dev/play/p/-xiPjy4JChJ)] + ### Attempt 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). -[[play](https://go.dev/play/p/M2wVq24PaZM)] +[[play](https://go.dev/play/p/1VS7HxlYMOG)] ### 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). -[[play](https://go.dev/play/p/cfcmhvLO-nv)] +[[play](https://go.dev/play/p/mhufUjJfLEF)] ### Debounce @@ -3876,6 +3931,8 @@ iterations, duration, ok := lo.WaitFor(laterTrue, 10*time.Millisecond, 5*time.Mi // false ``` +[[play](https://go.dev/play/p/t_wTDmubbK3)] + ### WaitForWithContext Runs periodically until a condition is validated or context is invalid. @@ -3918,6 +3975,8 @@ iterations, duration, ok := lo.WaitForWithContext(expiringCtx, alwaysFalse, 100* // false ``` +[[play](https://go.dev/play/p/t_wTDmubbK3)] + ### Validate Helper function that creates an error when a condition is not met. diff --git a/channel.go b/channel.go index d0cf6e9..bcc0f29 100644 --- a/channel.go +++ b/channel.go @@ -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. // Close events are propagated to children. // 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 { 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. // 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 { for { 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. // 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 { for { 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. // 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] { seq := []int{} @@ -123,6 +127,7 @@ func DispatchingStrategyWeightedRandom[T any](weights []int) DispatchingStrategy // 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. +// Play: https://go.dev/play/p/OrJCvOmk42f func DispatchingStrategyFirst[T any](msg T, index uint64, channels []<-chan T) int { for { 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. +// Play: https://go.dev/play/p/ypy0jrRcEe7 func DispatchingStrategyLeast[T any](msg T, index uint64, channels []<-chan T) int { 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. // 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 { 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. +// Play: https://go.dev/play/p/lIbSY3QmiEg func SliceToChannel[T any](bufferSize int, collection []T) <-chan T { 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. +// Play: https://go.dev/play/p/lIbSY3QmiEg func ChannelToSlice[T any](ch <-chan T) []T { collection := []T{} @@ -181,6 +190,7 @@ func ChannelToSlice[T any](ch <-chan T) []T { } // 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 { 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. // @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) { buffer := make([]T, 0, size) 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. // @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) { buffer := make([]T, 0, size) 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. +// 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) { ctx, cancel := context.WithTimeout(context.Background(), timeout) 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. // 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 { out := make(chan T, channelBufferCap) 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. // When upstream channel reach EOF, downstream channels close. If any downstream // 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 { downstreams := createChannels[T](count, channelsBufferCap) diff --git a/concurrency.go b/concurrency.go index 7c823b0..594db10 100644 --- a/concurrency.go +++ b/concurrency.go @@ -17,6 +17,7 @@ func (s *synchronize) Do(cb func()) { } // 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 if len(opt) > 1 { 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. +// Play: https://go.dev/play/p/uo35gosuTLw func Async[A any](f func() A) <-chan A { ch := make(chan A, 1) 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. +// Play: https://go.dev/play/p/tNqf1cClG_o func Async0(f func()) <-chan struct{} { ch := make(chan struct{}, 1) go func() { @@ -49,11 +52,13 @@ func Async0(f func()) <-chan struct{} { } // Async1 is an alias to Async. +// Play: https://go.dev/play/p/uo35gosuTLw func Async1[A any](f func() A) <-chan A { return Async(f) } // 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] { ch := make(chan Tuple2[A, B], 1) 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. +// Play: https://go.dev/play/p/L1d6o6l6q0d func Async3[A, B, C any](f func() (A, B, C)) <-chan Tuple3[A, B, C] { ch := make(chan Tuple3[A, B, C], 1) 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. +// 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] { ch := make(chan Tuple4[A, B, C, D], 1) 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. +// 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] { ch := make(chan Tuple5[A, B, C, D, E], 1) 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. +// 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] { ch := make(chan Tuple6[A, B, C, D, E, F], 1) 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. +// 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) { conditionWithContext := func(_ context.Context, currentIteration int) bool { 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. +// 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) { start := time.Now() diff --git a/errors.go b/errors.go index 3deb265..854c076 100644 --- a/errors.go +++ b/errors.go @@ -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 // 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 { must(err, messageArgs...) return val diff --git a/find.go b/find.go index 48affa7..4ca83a4 100644 --- a/find.go +++ b/find.go @@ -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 // if the value cannot be found. +// Play: https://go.dev/play/p/Eo7W0lvKTky func IndexOf[T comparable](collection []T, element T) int { for i := range collection { 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 // if the value cannot be found. +// Play: https://go.dev/play/p/Eo7W0lvKTky func LastIndexOf[T comparable](collection []T, element T) int { 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. +// Play: https://go.dev/play/p/Eo7W0lvKTky func Find[T any](collection []T, predicate func(item T) bool) (T, bool) { for i := range collection { 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. // 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) { for i := range collection { 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. // 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) { 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. +// Play: https://go.dev/play/p/Eo7W0lvKTky func FindOrElse[T any](collection []T, fallback T, predicate func(item T) bool) T { for i := range collection { 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. +// Play: https://go.dev/play/p/Bg0w1VDPYXx func FindKey[K comparable, V comparable](object map[K]V, value V) (K, bool) { for k := range object { 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. +// 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) { for k := range object { 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. // Returns zero value when the collection is empty. +// Play: https://go.dev/play/p/r6e-Z8JozS8 func Min[T constraints.Ordered](collection []T) 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. // Returns zero value when the collection is empty. +// Play: https://go.dev/play/p/r6e-Z8JozS8 func Max[T constraints.Ordered](collection []T) 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. +// Play: https://go.dev/play/p/ul45Z0y2EFO func First[T any](collection []T) (T, bool) { 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. +// Play: https://go.dev/play/p/ul45Z0y2EFO func FirstOrEmpty[T any](collection []T) T { i, _ := First(collection) return i } // 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 { i, ok := First(collection) 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. +// Play: https://go.dev/play/p/ul45Z0y2EFO func Last[T any](collection []T) (T, bool) { 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. +// Play: https://go.dev/play/p/ul45Z0y2EFO func LastOrEmpty[T any](collection []T) T { i, _ := Last(collection) return i } // 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 { i, ok := Last(collection) 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 // 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) { n := int(nth) 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. // 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. +// Play: https://go.dev/play/p/sHoh88KWt6B func NthOr[T any, N constraints.Integer](collection []T, nth N, fallback T) T { value, err := Nth(collection, nth) 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. // 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. +// Play: https://go.dev/play/p/sHoh88KWt6B func NthOrEmpty[T any, N constraints.Integer](collection []T, nth N) T { value, err := Nth(collection, nth) 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 // Sample returns a random item from collection. +// Play: https://go.dev/play/p/vCcSJbh5s6l func Sample[T any](collection []T) T { result := SampleBy(collection, rand.IntN) return result } // 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 { size := len(collection) if size == 0 { @@ -622,12 +643,14 @@ func SampleBy[T any](collection []T, randomIntGenerator randomIntGenerator) T { } // 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 { results := SamplesBy(collection, count, rand.IntN) return results } // 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 { size := len(collection) diff --git a/func.go b/func.go index 5fa1cbc..e734968 100644 --- a/func.go +++ b/func.go @@ -1,6 +1,7 @@ package lo // 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 { return func(t2 T2) R { 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. +// Play: https://go.dev/play/p/D-ASTXCLBzw func Partial1[T1, T2, R any](f func(T1, T2) R, arg1 T1) func(T2) R { return Partial(f, arg1) } // 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 { return func(t2 T2, t3 T3) R { 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. +// 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 { return func(t2 T2, t3 T3, t4 T4) R { 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. +// 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 { return func(t2 T2, t3 T3, t4 T4, t5 T5) R { 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 +// 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 { return func(t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) R { return f(arg1, t2, t3, t4, t5, t6) diff --git a/intersect.go b/intersect.go index c57bd81..0901492 100644 --- a/intersect.go +++ b/intersect.go @@ -1,6 +1,7 @@ package lo // 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 { for i := range collection { 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. +// Play: https://go.dev/play/p/W1EvyqY6t9j func ContainsBy[T any](collection []T, predicate func(item T) bool) bool { for i := range collection { 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. +// Play: https://go.dev/play/p/W1EvyqY6t9j func Every[T comparable](collection []T, subset []T) bool { for i := range subset { 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. +// Play: https://go.dev/play/p/dn1-vhHsq9x func EveryBy[T any](collection []T, predicate func(item T) bool) bool { for i := range collection { 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. // If the subset is empty Some returns false. +// Play: https://go.dev/play/p/Lj4ceFkeT9V func Some[T comparable](collection []T, subset []T) bool { for i := range subset { 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. // 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 { for i := range collection { 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. +// Play: https://go.dev/play/p/fye7JsmxzPV func None[T comparable](collection []T, subset []T) bool { for i := range subset { 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. +// Play: https://go.dev/play/p/O64WZ32H58S func NoneBy[T any](collection []T, predicate func(item T) bool) bool { for i := range collection { 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. +// Play: https://go.dev/play/p/uuElL9X9e58 func Intersect[T comparable, Slice ~[]T](list1 Slice, list2 Slice) Slice { result := Slice{} 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. // The first value is the collection of element absent of list2. // 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) { left := 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. // 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 { var capLen int @@ -166,6 +177,7 @@ func Union[T comparable, Slice ~[]T](lists ...Slice) Slice { } // 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 { excludeMap := make(map[T]struct{}, len(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. // 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 { excludeMap := make(map[K]struct{}, len(exclude)) for _, e := range exclude { @@ -206,6 +219,7 @@ func WithoutEmpty[T comparable, Slice ~[]T](collection Slice) Slice { } // WithoutNth returns slice excluding nth value. +// Play: https://go.dev/play/p/5g3F9R2H1xL func WithoutNth[T comparable, Slice ~[]T](collection Slice, nths ...int) Slice { 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). // 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. +// Play: https://go.dev/play/p/XWSEM4Ic_t0 func ElementsMatch[T comparable, Slice ~[]T](list1 Slice, list2 Slice) bool { 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). // 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. +// Play: https://go.dev/play/p/XWSEM4Ic_t0 func ElementsMatchBy[T any, K comparable](list1 []T, list2 []T, iteratee func(item T) K) bool { if len(list1) != len(list2) { return false diff --git a/map.go b/map.go index 3097735..83c7ce8 100644 --- a/map.go +++ b/map.go @@ -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. -// Play: +// Play: https://go.dev/play/p/_t4Xe34-Nl5 func Entries[K comparable, V any](in map[K]V) []Entry[K, V] { 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. // 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. +// 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 { result := make([]R, 0, len(in)) diff --git a/math.go b/math.go index 7c6ade3..0e75a3d 100644 --- a/math.go +++ b/math.go @@ -122,6 +122,7 @@ func ProductBy[T any, R constraints.Float | constraints.Integer | constraints.Co } // 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 { length := T(len(collection)) 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. +// Play: https://go.dev/play/p/j7TsVwBOZ7P func MeanBy[T any, R constraints.Float | constraints.Integer](collection []T, iteratee func(item T) R) R { length := R(len(collection)) if length == 0 { diff --git a/mutable/slice.go b/mutable/slice.go index 510e975..c244cd7 100644 --- a/mutable/slice.go +++ b/mutable/slice.go @@ -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. // 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. +// Play: https://go.dev/play/p/0jY3Z0B7O_5 func Filter[T any, Slice ~[]T](collection Slice, predicate func(item T) bool) Slice { j := 0 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 // 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) { for i := range collection { collection[i] = fn(collection[i]) diff --git a/parallel/slice.go b/parallel/slice.go index aa8df82..f92c93c 100644 --- a/parallel/slice.go +++ b/parallel/slice.go @@ -4,6 +4,7 @@ import "sync" // Map manipulates a slice and transforms it to a slice of another type. // `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 { 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. // `iteratee` is call in parallel. +// Play: https://go.dev/play/p/sCJaB3quRMC func ForEach[T any](collection []T, iteratee func(item T, index int)) { var wg sync.WaitGroup wg.Add(len(collection)) diff --git a/retry.go b/retry.go index 4138be0..0f84de9 100644 --- a/retry.go +++ b/retry.go @@ -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 // argument is less than `1`, the function runs until a successful response is // returned. +// Play: https://go.dev/play/p/1VS7HxlYMOG func AttemptWhile(maxIteration int, f func(int) (error, bool)) (int, error) { var err error 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. // When the first argument is less than `1`, the function runs until a successful // 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) { var err error var shouldContinueInvoke bool @@ -247,6 +249,7 @@ type transactionStep[T any] struct { } // NewTransaction instantiate a new transaction. +// Play: https://go.dev/play/p/Qxrd7MGQGh1 func NewTransaction[T any]() *Transaction[T] { return &Transaction[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. +// 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] { t.steps = append(t.steps, transactionStep[T]{ 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. +// Play: https://go.dev/play/p/Qxrd7MGQGh1 https://go.dev/play/p/xrHb2_kMvTY func (t *Transaction[T]) Process(state T) (T, error) { var i int 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. // 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()) { return NewThrottleWithCount(interval, 1, f...) } // 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()) { callbacks := Map(f, func(item func(), _ int) 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. // 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()) { return NewThrottleByWithCount[T](interval, 1, f...) } // 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()) { if count <= 0 { count = 1 diff --git a/slice.go b/slice.go index ee63e42..7a0c6a8 100644 --- a/slice.go +++ b/slice.go @@ -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. +// Play: https://go.dev/play/p/fygzLBhvUdB func UniqMap[T any, R comparable](collection []T, iteratee func(item T, index int) R) []R { result := make([]R, 0, 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 // - 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 { 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. // The transform function can either return a slice or a `nil`, and in the `nil` case // 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 { 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 // 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 { for i := range collection { 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. +// 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 { 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, // 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 { if size <= 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. -// 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 { 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. // 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. +// 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 { 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. +// Play: https://go.dev/play/p/RYhhM_csqIG func Keyify[T comparable, Slice ~[]T](collection Slice) map[T]struct{} { 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. -// 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 { 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 result of the mapping operation and // - 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 { 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 // 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) { kept = make(Slice, 0, len(collection)) rejected = make(Slice, 0, len(collection)) diff --git a/string.go b/string.go index 5581b61..ba69f15 100644 --- a/string.go +++ b/string.go @@ -151,6 +151,7 @@ func RuneLength(str string) int { } // PascalCase converts string to pascal case. +// Play: https://go.dev/play/p/Dy_V_6DUYhe func PascalCase(str string) string { items := Words(str) for i := range items { @@ -160,6 +161,7 @@ func PascalCase(str string) string { } // CamelCase converts string to camel case. +// Play: https://go.dev/play/p/Go6aKwUiq59 func CamelCase(str string) string { items := Words(str) for i, item := range items { @@ -173,6 +175,7 @@ func CamelCase(str string) string { } // KebabCase converts string to kebab case. +// Play: https://go.dev/play/p/96gT_WZnTVP func KebabCase(str string) string { items := Words(str) for i := range items { @@ -182,6 +185,7 @@ func KebabCase(str string) string { } // SnakeCase converts string to snake case. +// Play: https://go.dev/play/p/ziB0V89IeVH func SnakeCase(str string) string { items := Words(str) for i := range items { @@ -191,6 +195,7 @@ func SnakeCase(str string) string { } // Words splits string into an array of its words. +// Play: https://go.dev/play/p/-f3VIQqiaVw func Words(str string) []string { str = splitWordReg.ReplaceAllString(str, `$1$3$5$7 $2$4$6$8$9`) // 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. +// Play: https://go.dev/play/p/uLTZZQXqnsa func Capitalize(str string) string { 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 // 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. +// Play: https://go.dev/play/p/qE93rgqe1TW func Ellipsis(str string, length int) string { str = strings.TrimSpace(str) diff --git a/time.go b/time.go index e98e80f..1e3b827 100644 --- a/time.go +++ b/time.go @@ -3,11 +3,13 @@ package lo import "time" // Duration returns the time taken to execute a function. +// Play: https://go.dev/play/p/HQfbBbAXaFP func Duration(cb func()) time.Duration { return Duration0(cb) } // Duration0 returns the time taken to execute a function. +// Play: https://go.dev/play/p/HQfbBbAXaFP func Duration0(cb func()) time.Duration { start := time.Now() cb() @@ -15,6 +17,7 @@ func Duration0(cb func()) time.Duration { } // 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) { start := time.Now() 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. +// Play: https://go.dev/play/p/HQfbBbAXaFP func Duration2[A, B any](cb func() (A, B)) (A, B, time.Duration) { start := time.Now() 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. +// Play: https://go.dev/play/p/xr863iwkAxQ func Duration3[A, B, C any](cb func() (A, B, C)) (A, B, C, time.Duration) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() 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. +// 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) { start := time.Now() a, b, c, d, e, f, g, h, i, j := cb() diff --git a/tuples.go b/tuples.go index 4cebda8..a0539e0 100644 --- a/tuples.go +++ b/tuples.go @@ -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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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. +// 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 { 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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 // 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) { size := len(items) 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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. // It is the cartesian product of lists received as arguments. // 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] { 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) 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 // is used to create the output values. // 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 { size := len(listA) * len(listB) * len(listC) * len(listD) * len(listE) * len(listF) * len(listG) * len(listH) * len(listI) if size == 0 { diff --git a/type_manipulation.go b/type_manipulation.go index 106ee94..fa5f444 100644 --- a/type_manipulation.go +++ b/type_manipulation.go @@ -3,28 +3,33 @@ package lo import "reflect" // 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 { defer func() { recover() }() // nolint:errcheck 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. +// Play: https://go.dev/play/p/P2sD0PMXw4F func IsNotNil(x any) bool { return !IsNil(x) } // ToPtr returns a pointer copy of value. +// Play: https://go.dev/play/p/P2sD0PMXw4F func ToPtr[T any](x T) *T { return &x } // Nil returns a nil pointer of type. +// Play: https://go.dev/play/p/P2sD0PMXw4F func Nil[T any]() *T { return nil } // EmptyableToPtr returns a pointer copy of value if it's nonzero. // Otherwise, returns nil pointer. +// Play: https://go.dev/play/p/P2sD0PMXw4F func EmptyableToPtr[T any](x T) *T { // 🤮 isZero := reflect.ValueOf(&x).Elem().IsZero() @@ -36,6 +41,7 @@ func EmptyableToPtr[T any](x T) *T { } // FromPtr returns the pointer value or empty. +// Play: https://go.dev/play/p/mhD9CwO3X0m func FromPtr[T any](x *T) T { if x == nil { return Empty[T]() @@ -45,6 +51,7 @@ func FromPtr[T any](x *T) T { } // 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 { if x == nil { return fallback @@ -54,6 +61,7 @@ func FromPtrOr[T any](x *T, fallback T) T { } // ToSlicePtr returns a slice of pointer copy of value. +// Play: https://go.dev/play/p/P2sD0PMXw4F func ToSlicePtr[T any](collection []T) []*T { result := make([]*T, len(collection)) @@ -65,6 +73,7 @@ func ToSlicePtr[T any](collection []T) []*T { // FromSlicePtr returns a slice with the pointer values. // 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 { return Map(collection, func(x *T, _ int) T { 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 +// Play: https://go.dev/play/p/P2sD0PMXw4F func ToAnySlice[T any](collection []T) []any { result := make([]any, len(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. // 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) { defer func() { 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). +// Play: https://go.dev/play/p/P2sD0PMXw4F func Empty[T any]() T { var zero T return zero } // IsEmpty returns true if argument is a zero value. +// Play: https://go.dev/play/p/P2sD0PMXw4F func IsEmpty[T comparable](v T) bool { var zero T return zero == v } // IsNotEmpty returns true if argument is not a zero value. +// Play: https://go.dev/play/p/P2sD0PMXw4F func IsNotEmpty[T comparable](v T) bool { var zero T return zero != v } // 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) { for i := range values { 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. +// Play: https://go.dev/play/p/Gyo9otyvFHH func CoalesceOrEmpty[T comparable](v ...T) T { result, _ := Coalesce(v...) return result } // CoalesceSlice returns the first non-zero slice. +// Play: https://go.dev/play/p/Gyo9otyvFHH func CoalesceSlice[T any](v ...[]T) ([]T, bool) { for i := range v { 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. +// Play: https://go.dev/play/p/Gyo9otyvFHH func CoalesceSliceOrEmpty[T any](v ...[]T) []T { for i := range v { 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. +// Play: https://go.dev/play/p/Gyo9otyvFHH func CoalesceMap[K comparable, V any](v ...map[K]V) (map[K]V, bool) { for i := range v { 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. +// Play: https://go.dev/play/p/Gyo9otyvFHH func CoalesceMapOrEmpty[K comparable, V any](v ...map[K]V) map[K]V { for i := range v { if v[i] != nil && len(v[i]) > 0 { diff --git a/types.go b/types.go index 1c6f0d0..2ba39aa 100644 --- a/types.go +++ b/types.go @@ -13,6 +13,7 @@ type Tuple2[A, B any] struct { } // Unpack returns values contained in tuple. +// Play: https://go.dev/play/p/yrtn7QJTmL_E func (t Tuple2[A, B]) Unpack() (A, B) { return t.A, t.B } @@ -25,6 +26,7 @@ type Tuple3[A, B, C any] struct { } // Unpack returns values contained in tuple. +// Play: https://go.dev/play/p/yrtn7QJTmL_E func (t Tuple3[A, B, C]) Unpack() (A, B, 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. +// Play: https://go.dev/play/p/yrtn7QJTmL_E func (t Tuple4[A, B, C, D]) Unpack() (A, B, C, 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. +// Play: https://go.dev/play/p/7J4KrtgtK3M 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 } @@ -67,6 +71,7 @@ type Tuple6[A, B, C, D, E, F any] struct { } // 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) { 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. +// 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) { 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. +// 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) { 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. +// 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) { return t.A, t.B, t.C, t.D, t.E, t.F, t.G, t.H, t.I }