summaryrefslogtreecommitdiff
path: root/src/slices
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2023-04-07 14:03:55 -0700
committerGopher Robot <gobot@golang.org>2023-04-07 22:25:51 +0000
commit693a34e78856980b0bb4a10ffcfd2bac1dbd6ebe (patch)
tree11b735cf8f85b666be5a5127235f0257456112ef /src/slices
parentb3bc8620f89153fddc1a30ee17c1d93654ed4314 (diff)
downloadgo-git-693a34e78856980b0bb4a10ffcfd2bac1dbd6ebe.tar.gz
slices: add DeleteFunc
Fixes #54768 Change-Id: I588ae33c13e0bbd9d324c11771667b22a864047d Reviewed-on: https://go-review.googlesource.com/c/go/+/483175 Reviewed-by: Ian Lance Taylor <iant@google.com> Auto-Submit: Ian Lance Taylor <iant@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Eli Bendersky <eliben@google.com> Run-TryBot: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src/slices')
-rw-r--r--src/slices/slices.go26
-rw-r--r--src/slices/slices_test.go46
2 files changed, 72 insertions, 0 deletions
diff --git a/src/slices/slices.go b/src/slices/slices.go
index 1a837c53c1..ea1dea573c 100644
--- a/src/slices/slices.go
+++ b/src/slices/slices.go
@@ -109,6 +109,32 @@ func Delete[S ~[]E, E any](s S, i, j int) S {
return append(s[:i], s[j:]...)
}
+// DeleteFunc removes any elements from s for which del returns true,
+// returning the modified slice.
+// DeleteFunc modifies the contents of the slice s;
+// it does not create a new slice.
+// When DeleteFunc removes m elements, it might not modify the elements
+// s[len(s)-m:len(s)]. If those elements contain pointers you might consider
+// zeroing those elements so that objects they reference can be garbage
+// collected.
+func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
+ // Don't start copying elements until we find one to delete.
+ for i, v := range s {
+ if del(v) {
+ j := i
+ for i++; i < len(s); i++ {
+ v = s[i]
+ if !del(v) {
+ s[j] = v
+ j++
+ }
+ }
+ return s[:j]
+ }
+ }
+ return s
+}
+
// Replace replaces the elements s[i:j] by the given v, and returns the
// modified slice. Replace panics if s[i:j] is not a valid slice of s.
func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
diff --git a/src/slices/slices_test.go b/src/slices/slices_test.go
index 80efb34fc8..720e731ddf 100644
--- a/src/slices/slices_test.go
+++ b/src/slices/slices_test.go
@@ -304,6 +304,52 @@ func TestDelete(t *testing.T) {
}
}
+var deleteFuncTests = []struct {
+ s []int
+ fn func(int) bool
+ want []int
+}{
+ {
+ nil,
+ func(int) bool { return true },
+ nil,
+ },
+ {
+ []int{1, 2, 3},
+ func(int) bool { return true },
+ nil,
+ },
+ {
+ []int{1, 2, 3},
+ func(int) bool { return false },
+ []int{1, 2, 3},
+ },
+ {
+ []int{1, 2, 3},
+ func(i int) bool { return i > 2 },
+ []int{1, 2},
+ },
+ {
+ []int{1, 2, 3},
+ func(i int) bool { return i < 2 },
+ []int{2, 3},
+ },
+ {
+ []int{10, 2, 30},
+ func(i int) bool { return i >= 10 },
+ []int{2},
+ },
+}
+
+func TestDeleteFunc(t *testing.T) {
+ for i, test := range deleteFuncTests {
+ copy := Clone(test.s)
+ if got := DeleteFunc(copy, test.fn); !Equal(got, test.want) {
+ t.Errorf("DeleteFunc case %d: got %v, want %v", i, got, test.want)
+ }
+ }
+}
+
func panics(f func()) (b bool) {
defer func() {
if x := recover(); x != nil {