diff --git a/README.md b/README.md index f9ccde38..4f18c4fb 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ Supported helpers for slices: - [CountValuesBy](#countvaluesby) - [Subset](#subset) - [Slice](#slice) +- [Concat](#concat) - [Replace](#replace) - [ReplaceAll](#replaceall) - [Compact](#compact) @@ -906,6 +907,21 @@ slice := lo.Slice(in, 4, 3) [[play](https://go.dev/play/p/8XWYhfMMA1h)] +### Concat + +Returns a new slice containing all the elements in collections. Concat conserves the order of the elements. + +```go +slice := lo.Concat([]int{1, 2}, []int{3, 4}) +// []int{1, 2, 3, 4} + +slice := lo.Concat(nil, []int{1, 2}, nil, []int{3, 4}, nil) +// []int{1, 2, 3, 4} + +slice := lo.Concat[int]() +// []int{} +``` + ### Replace Returns a copy of the slice with the first n non-overlapping instances of old replaced by new. diff --git a/slice.go b/slice.go index 54d1b004..545f0eea 100644 --- a/slice.go +++ b/slice.go @@ -562,6 +562,23 @@ func Slice[T any](collection []T, start int, end int) []T { return collection[start:end] } +// Concat returns a new slice containing all the elements in +// collections. Concat conserves the order of the elements. +func Concat[T any](collections ...[]T) []T { + size := 0 + for i := range collections { + size += len(collections[i]) + } + + result := make([]T, 0, size) // preallocate memory for the output slice + for i := 0; i < len(collections); i++ { + // `result` memory address is not expected to change, because we preallocated enough memory + result = append(result, collections[i]...) + } + + return result +} + // Replace returns a copy of the slice with the first n non-overlapping instances of old replaced by new. // Play: https://go.dev/play/p/XfPzmf9gql6 func Replace[T comparable](collection []T, old T, new T, n int) []T { diff --git a/slice_test.go b/slice_test.go index cd3ee829..48d43f89 100644 --- a/slice_test.go +++ b/slice_test.go @@ -689,6 +689,16 @@ func TestSlice(t *testing.T) { is.Equal([]int{0, 1, 2, 3, 4}, out18) } +func TestConcat(t *testing.T) { + t.Parallel() + is := assert.New(t) + + is.Equal([]int{1, 2, 3, 4}, Concat([]int{1, 2}, []int{3, 4})) + is.Equal([]int{1, 2, 3, 4}, Concat(nil, []int{1, 2}, nil, []int{3, 4}, nil)) + is.Equal([]int{}, Concat[int](nil, nil)) + is.Equal([]int{}, Concat[int]()) +} + func TestReplace(t *testing.T) { t.Parallel() is := assert.New(t)