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
+}