From 5cdecc5bf4c1b4b6cb4b644f167bbee5a1d65d01 Mon Sep 17 00:00:00 2001 From: Matt Oestreich <21092343+oze4@users.noreply.github.com> Date: Wed, 14 Aug 2024 13:58:49 -0500 Subject: [PATCH] Add Splice function --- README.md | 75 ++++++++++++++++++++++ jslice_test.go | 170 +++++++++++++++++++++++++++++++++++++++++++++++-- splice.go | 29 +++++++++ 3 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 splice.go diff --git a/README.md b/README.md index 67f995c..89bc3a5 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,81 @@ r := jslice.Slice(s, start, end) // r == []int{1,2,3} ``` +## Splice + +Changes the contents of a slice by removing or replacing existing elements and/or adding new elements. + +- If `deleteCount` and `replacementElements` both equal `0`, we just return the original slice without modifying anything. +- If `start` is greater than or equal to the length of the slice, no elements will be deleted, but the method will behave as an adding function. + +Remove `0` elements before index `2` and insert "`earth`" and "`mars`" +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 2, 0, "earth", "mars") +// s == []string{"mercury", "venus", "earth", "mars", "jupiter", "saturn"} +``` + +**Remove `0` elements at index `0` and insert "`earth`" and "`mars`".** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 0, 0, "earth", "mars") +// s == []string{"earth", "mars", "mercury", "venus", "jupiter", "saturn"} +``` + +**Remove `1` element at index `2`, and insert "`earth`" and "`mars`"** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 2, 1, "earth", "mars") +// s == []string{"mercury", "venus", "earth", "mars", "saturn"} +``` + +**Remove `1` element at index `0` and insert "`earth`" and "`mars`"** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 0, 1, "earth", "mars") +// s == []string{"earth", "mars", "venus", "jupiter", "saturn"} +``` + +**Remove `3` elements starting at index `1` and insert nothing** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 1, 3) +// s == []string{"mercury"} +``` + +**If `start` + `deleteCount` is greater than or equal to slice length, we modify `deleteCount` to equal the length of the slice - `start`** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 2, 100) // <- 100 greater than slice length +// s == []string{"mercury", "venus"} +``` + +**If `start` is greater than or equal to the length of the slice, no elements are removed, but the method is treated as an add function** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +// Even though `deleteCount` == 1, nothing will be +// deleted because `start` >= length of slice. +jslice.Splice(&s, 100, 1, "earth", "mars") +// s == []string{"mercury", "venus", "jupiter", "saturn", "earth", "mars"} +``` + +**Splice last element by removing `1` element at index `3` and inserting "`earth`" and "`mars`"** + +```go +s := []string{"mercury", "venus", "jupiter", "saturn"} +jslice.Splice(&s, 3, 1, "earth", "mars") +// s == []string{"mercury", "venus", "jupiter", "earth", "mars"} +``` + + + +


diff --git a/jslice_test.go b/jslice_test.go index 40b78a8..e0b487d 100644 --- a/jslice_test.go +++ b/jslice_test.go @@ -160,7 +160,7 @@ func TestEvery(t *testing.T) { func TestSlice(t *testing.T) { const ( - EXPECT_OG_LEN = 5 + EXPECT_OG_LEN = 5 EXPECT_SLICED_LEN = 3 ) s := []int{1, 2, 3, 4, 5} @@ -177,21 +177,183 @@ func TestSlice(t *testing.T) { func TestShift(t *testing.T) { const ( - EXPECT_OG_LEN = 3 + EXPECT_OG_LEN = 3 EXPECT_RESULT_VAL = 1 ) - s := []int{1,2,3,4} + s := []int{1, 2, 3, 4} r := jslice.Shift(&s) if len(s) != EXPECT_OG_LEN { t.Fatalf("Expected original slice length to now be = %d | Got = %d\n", EXPECT_OG_LEN, len(s)) } - if (r != EXPECT_RESULT_VAL) { + if r != EXPECT_RESULT_VAL { t.Fatalf("Expected result value to be = %d | Got = %d\n", EXPECT_RESULT_VAL, r) } t.Log(s) t.Log(r) } +func TestSplice_StartIndex2_Delete0_Insert2(t *testing.T) { + EXPECT := []string{"mercury", "venus", "earth", "mars", "jupiter", "saturn"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 2, 0, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndex0_Delete0_Insert2(t *testing.T) { + EXPECT := []string{"earth", "mars", "mercury", "venus", "jupiter", "saturn"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 0, 0, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndex2_Delete1_Insert2(t *testing.T) { + EXPECT := []string{"mercury", "venus", "earth", "mars", "saturn"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 2, 1, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndex0_Delete1_Insert2(t *testing.T) { + EXPECT := []string{"earth", "mars", "venus", "jupiter", "saturn"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 0, 1, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndex1_DeleteCount0_Insert0(t *testing.T) { + EXPECT := []string{"mercury"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 1, 3) + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_DeleteCountGreaterThanSliceLen(t *testing.T) { + EXPECT := []string{"mercury", "venus"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 2, 100) + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndexGreaterThanSliceLen_WithoutReplacementItems(t *testing.T) { + EXPECT := []string{"mercury", "venus", "jupiter", "saturn"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 100, 100) + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_StartIndexGreaterThanSliceLen_WithReplacementItems(t *testing.T) { + EXPECT := []string{"mercury", "venus", "jupiter", "saturn", "earth", "mars"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 100, 1, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + +func TestSplice_SpliceLastElement(t *testing.T) { + EXPECT := []string{"mercury", "venus", "jupiter", "earth", "mars"} + s := []string{"mercury", "venus", "jupiter", "saturn"} + + jslice.Splice(&s, 3, 1, "earth", "mars") + + if len(EXPECT) != len(s) { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + // use jslice to help with testing ;) + jslice.ForEach(s, func(i int, e string) { + if EXPECT[i] != e { + t.Fatalf("\nExpected\t= %v\nGot\t\t= %v\n", EXPECT, s) + } + }) + t.Log(s) +} + // ************************************************************** func TestTest(t *testing.T) { diff --git a/splice.go b/splice.go new file mode 100644 index 0000000..75c6375 --- /dev/null +++ b/splice.go @@ -0,0 +1,29 @@ +package jslice + +// Splice changes the contents of a slice by removing or replacing existing elements, +// and/or adding new elements. +func Splice[T any](s *[]T, start uint, deleteCount uint, replacementItems ...T) { + if deleteCount == 0 && len(replacementItems) == 0 { + return //*s + } + + // If start >= len(*s) no elements will be deleted, but the method will behave as + // an adding function. + if start >= uint(len(*s)) { + if len(replacementItems) == 0 { + return //*s + } + *s = append(*s, replacementItems...) + return //*s + } + + // If the "end" (start+deleteCount) is greater than the length of the slice, limit + // the delete count to the length of the slice - start. Otherwise we get index out + // of bounds error. + if start + deleteCount >= uint(len(*s)) { + deleteCount = uint(len(*s)) - start + } + + *s = append((*s)[0:start], append(replacementItems, (*s)[start+deleteCount:]...)...) + return //*s +}