From 0066bed1a0ffee999cdccf9f48aadf62d3d1ed0d Mon Sep 17 00:00:00 2001 From: wenlingang Date: Thu, 3 Aug 2023 13:20:24 +0800 Subject: [PATCH 1/6] Add slice Splice an element or multiple elements at index i. --- README.md | 12 ++++++++++++ slice.go | 12 ++++++++++++ slice_test.go | 13 +++++++++++++ 3 files changed, 37 insertions(+) diff --git a/README.md b/README.md index 0f09c7bc..72e1c098 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,7 @@ Supported helpers for slices: - [Compact](#compact) - [IsSorted](#issorted) - [IsSortedByKey](#issortedbykey) +- [Splice](#Splice) Supported helpers for maps: @@ -980,6 +981,17 @@ slice := lo.IsSortedByKey([]string{"a", "bb", "ccc"}, func(s string) int { [[play](https://go.dev/play/p/wiG6XyBBu49)] +### Splice + +Splice multiple elements at index i. + +```go +result := lo.Splice([]string{"a", "d"}, 1, "b", "c") +// []string{"a", "b", "c", "d"} +``` + +[[play](https://go.dev/play/p/8gXdkTovsIC)] + ### Keys Creates an array of the map keys. diff --git a/slice.go b/slice.go index 7ef820ad..f2990cdf 100644 --- a/slice.go +++ b/slice.go @@ -625,3 +625,15 @@ func IsSortedByKey[T any, K constraints.Ordered](collection []T, iteratee func(i return true } + +// Play: https://go.dev/play/p/G5_GhkeSUBA +func Splice[T any](collection []T, i int, elements ...T) []T { + if i < 0 || i > len(collection) { + panic("index out of bounds") + } + if len(elements) == 0 { + return collection + } + + return append(append(collection[:i], elements...), collection[i:]...) +} diff --git a/slice_test.go b/slice_test.go index e7e717fd..23b63947 100644 --- a/slice_test.go +++ b/slice_test.go @@ -801,3 +801,16 @@ func TestIsSortedByKey(t *testing.T) { return ret })) } + +func TestInsertSlice(t *testing.T) { + t.Parallel() + is := assert.New(t) + + inserts := Splice([]string{"a", "d"}, 1, "b", "c") + is.Equal(inserts, []string{"a", "b", "c", "d"}) + is.True(len(inserts) == 4 && inserts[1] == "b" && inserts[2] == "c") + + inserti := Splice([]int{1, 4}, 1, 2, 3) + is.Equal(inserti, []int{1, 2, 3, 4}) + is.True(len(inserti) == 4 && inserti[1] == 2 && inserti[2] == 3) +} From 743929fcc1c7d6130b381ee7c4acb0fdfb57f68e Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sat, 29 Jun 2024 18:08:11 +0200 Subject: [PATCH 2/6] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 72e1c098..2922366d 100644 --- a/README.md +++ b/README.md @@ -983,14 +983,14 @@ slice := lo.IsSortedByKey([]string{"a", "bb", "ccc"}, func(s string) int { ### Splice -Splice multiple elements at index i. +Insert multiple elements at index i. ```go result := lo.Splice([]string{"a", "d"}, 1, "b", "c") // []string{"a", "b", "c", "d"} ``` -[[play](https://go.dev/play/p/8gXdkTovsIC)] +[[play](https://go.dev/play/p/G5_GhkeSUBA)] ### Keys From 73f1b27a8cae560dda454becb691b36b8bf09423 Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sat, 29 Jun 2024 18:09:09 +0200 Subject: [PATCH 3/6] Update slice.go --- slice.go | 1 + 1 file changed, 1 insertion(+) diff --git a/slice.go b/slice.go index f2990cdf..3b145146 100644 --- a/slice.go +++ b/slice.go @@ -626,6 +626,7 @@ func IsSortedByKey[T any, K constraints.Ordered](collection []T, iteratee func(i return true } +// Splice inserts multiple elements at index i. // Play: https://go.dev/play/p/G5_GhkeSUBA func Splice[T any](collection []T, i int, elements ...T) []T { if i < 0 || i > len(collection) { From f27673ec8cb82744a932070bbbb53c3bb86129d4 Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sat, 29 Jun 2024 20:11:43 +0200 Subject: [PATCH 4/6] Update slice.go --- slice.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/slice.go b/slice.go index 3b145146..5c794d79 100644 --- a/slice.go +++ b/slice.go @@ -626,15 +626,26 @@ func IsSortedByKey[T any, K constraints.Ordered](collection []T, iteratee func(i return true } -// Splice inserts multiple elements at index i. +// Splice inserts multiple elements at index i. A negative index counts back +// from the end of the slice. The helper is protected against overflow errors. // Play: https://go.dev/play/p/G5_GhkeSUBA func Splice[T any](collection []T, i int, elements ...T) []T { - if i < 0 || i > len(collection) { - panic("index out of bounds") - } - if len(elements) == 0 { - return collection - } - - return append(append(collection[:i], elements...), collection[i:]...) + sizeCollection := len(collection) + sizeElements := len(elements) + output := make([]T, 0, sizeCollection+sizeElements) // preallocate memory for the output slice + + if sizeElements == 0 { + return append(output, collection...) // simple copy + } else if i > sizeCollection { + // positive overflow + return append(append(output, collection...), elements...) + } else if i < -sizeCollection { + // negative overflow + return append(append(output, elements...), collection...) + } else if i < 0 { + // backward + i = sizeCollection + i + } + + return append(append(append(output, collection[:i]...), elements...), collection[i:]...) } From ba8e62c6bd40fcc2fe32dcc782789974d21b6650 Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sat, 29 Jun 2024 20:13:54 +0200 Subject: [PATCH 5/6] Update README.md --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2922366d..f9ccde38 100644 --- a/README.md +++ b/README.md @@ -983,11 +983,19 @@ slice := lo.IsSortedByKey([]string{"a", "bb", "ccc"}, func(s string) int { ### Splice -Insert multiple elements at index i. +Splice inserts multiple elements at index i. A negative index counts back from the end of the slice. The helper is protected against overflow errors. ```go -result := lo.Splice([]string{"a", "d"}, 1, "b", "c") -// []string{"a", "b", "c", "d"} +result := lo.Splice([]string{"a", "b"}, 1, "1", "2") +// []string{"a", "1", "2", "b"} + +// negative +result = lo.Splice([]string{"a", "b"}, -1, "1", "2") +// []string{"a", "1", "2", "b"} + +// overflow +result = lo.Splice([]string{"a", "b"}, 42, "1", "2") +// []string{"a", "b", "1", "2"} ``` [[play](https://go.dev/play/p/G5_GhkeSUBA)] From 43786c0a1813e7c90a2790733bdfa3aa434ca44e Mon Sep 17 00:00:00 2001 From: Samuel Berthe Date: Sat, 29 Jun 2024 20:14:17 +0200 Subject: [PATCH 6/6] Update slice_test.go --- slice_test.go | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/slice_test.go b/slice_test.go index 23b63947..cd3ee829 100644 --- a/slice_test.go +++ b/slice_test.go @@ -802,15 +802,46 @@ func TestIsSortedByKey(t *testing.T) { })) } -func TestInsertSlice(t *testing.T) { +func TestSplice(t *testing.T) { t.Parallel() is := assert.New(t) - inserts := Splice([]string{"a", "d"}, 1, "b", "c") - is.Equal(inserts, []string{"a", "b", "c", "d"}) - is.True(len(inserts) == 4 && inserts[1] == "b" && inserts[2] == "c") + sample := []string{"a", "b", "c", "d", "e", "f", "g"} - inserti := Splice([]int{1, 4}, 1, 2, 3) - is.Equal(inserti, []int{1, 2, 3, 4}) - is.True(len(inserti) == 4 && inserti[1] == 2 && inserti[2] == 3) + // normal case + results := Splice(sample, 1, "1", "2") + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + is.Equal([]string{"a", "1", "2", "b", "c", "d", "e", "f", "g"}, results) + + // check there is no side effect + results = Splice(sample, 1) + results[0] = "b" + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + + // positive overflow + results = Splice(sample, 42, "1", "2") + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + is.Equal(results, []string{"a", "b", "c", "d", "e", "f", "g", "1", "2"}) + + // negative overflow + results = Splice(sample, -42, "1", "2") + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + is.Equal(results, []string{"1", "2", "a", "b", "c", "d", "e", "f", "g"}) + + // backard + results = Splice(sample, -2, "1", "2") + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + is.Equal(results, []string{"a", "b", "c", "d", "e", "1", "2", "f", "g"}) + + results = Splice(sample, -7, "1", "2") + is.Equal([]string{"a", "b", "c", "d", "e", "f", "g"}, sample) + is.Equal(results, []string{"1", "2", "a", "b", "c", "d", "e", "f", "g"}) + + // other + is.Equal([]string{"1", "2"}, Splice([]string{}, 0, "1", "2")) + is.Equal([]string{"1", "2"}, Splice([]string{}, 1, "1", "2")) + is.Equal([]string{"1", "2"}, Splice([]string{}, -1, "1", "2")) + is.Equal([]string{"1", "2", "0"}, Splice([]string{"0"}, 0, "1", "2")) + is.Equal([]string{"0", "1", "2"}, Splice([]string{"0"}, 1, "1", "2")) + is.Equal([]string{"1", "2", "0"}, Splice([]string{"0"}, -1, "1", "2")) }