Skip to content

Commit

Permalink
transform: add ChunkBy
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeydobrodey committed Jan 23, 2025
1 parent 104249d commit 63d4339
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ This package provides several functions for working with collections:
* `AsyncTryTransformBy[T, K any](parent context.Context, source []T, transform func(context.Context, T) (K, error)) ([]K, error)`
* `ChannelsMerge[T any](args ...<-chan T) <-chan T`
* `ChannelsReadonly[T any](args ...chan T) []<-chan T`
* `ChunkBy[T any](source []T, size int) [][]T`
* `Contains[T comparable](source []T, item T) bool`
* `Copy[T any](source []T) []T`
* `Difference[T comparable](a []T, b []T) []T`
Expand Down
20 changes: 20 additions & 0 deletions transform.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@ func Duplicates[T comparable](source []T) []T {
return Distinct(result)
}

// ChunkBy divides a slice of Type T into smaller chunks of the specified size.
func ChunkBy[T any](source []T, size int) [][]T {
if size <= 0 || len(source) == 0 {
return nil
}

var chunks = make([][]T, 0, len(source)/size)

for i := 0; i < len(source); i += size {
var end = i + size
if end > len(source) {
end = len(source)
}

chunks = append(chunks, source[i:end])
}

return chunks
}

// AsyncTransformBy async transform the source slice of type T to a new slice of type K using the provided transform function.
func AsyncTransformBy[T, K any](source []T, transform func(T) K) []K {
var results = make([]K, len(source))
Expand Down
62 changes: 62 additions & 0 deletions transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -447,3 +447,65 @@ func TestAsyncTransformBy(t *testing.T) {
})
}
}

func TestChunkBy(t *testing.T) {
cases := []struct {
name string
source []int
size int
want [][]int
}{
{
name: "evenly divisible chunks",
source: []int{1, 2, 3, 4, 5, 6},
size: 2,
want: [][]int{{1, 2}, {3, 4}, {5, 6}},
},
{
name: "remainder chunk",
source: []int{1, 2, 3, 4, 5},
size: 2,
want: [][]int{{1, 2}, {3, 4}, {5}},
},
{
name: "chunk size larger than source",
source: []int{1, 2, 3},
size: 5,
want: [][]int{{1, 2, 3}},
},
{
name: "chunk size equal to source length",
source: []int{1, 2, 3},
size: 3,
want: [][]int{{1, 2, 3}},
},
{
name: "empty source slice",
source: []int{},
size: 3,
want: nil,
},
{
name: "zero chunk size",
source: []int{1, 2, 3},
size: 0,
want: nil,
},
{
name: "negative chunk size",
source: []int{1, 2, 3},
size: -1,
want: nil,
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := collection.ChunkBy(tc.source, tc.size)

if !slices.EqualFunc(got, tc.want, slices.Equal[[]int]) {
t.Errorf("ChunkBy(%v, %d) = %v; want %v", tc.source, tc.size, got, tc.want)
}
})
}
}

0 comments on commit 63d4339

Please sign in to comment.