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>
This commit is contained in:
Ian Lance Taylor 2023-04-07 14:03:55 -07:00 committed by Gopher Robot
parent b3bc8620f8
commit 693a34e788
3 changed files with 73 additions and 0 deletions

1
api/next/54768.txt Normal file
View file

@ -0,0 +1 @@
pkg slices, func DeleteFunc[$0 interface{ ~[]$1 }, $1 interface{}]($0, func($1) bool) $0 #54768

View file

@ -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 {

View file

@ -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 {